From 56d04499d340e4a1458490d1f87c594c40835c6a Mon Sep 17 00:00:00 2001 From: MendixMau Date: Fri, 21 Aug 2026 21:34:18 +0700 Subject: [PATCH 1/2] Correct the false Studio Pro dependency in the cloud/mobile prompts commands/mobile-dev-loop-prompt.md asserted that the build gate requires Studio Pro and that a headless container therefore cannot run it. That is wrong, and it was stopping cloud sessions at a boundary that does not exist: the gate is mxbuild, a plain binary that project-bin/exec.sh invokes directly, and exec.sh's only Studio Pro coupling is a lock check (refuse to write while SP holds the .mpr) which is a no-op where no SP exists. Both prompts also predate mxcli run --local / --hub / --test-endpoint, which the toolkit did not mention anywhere. A container can now stand the app up itself and publish it at a public URL, so the hand-rolled ngrok/cloudflared tunnel is no longer the only route in. - mobile-dev-loop-prompt.md: dated correction note; DO-NOT list reframed as out-of-scope-for-this-prompt rather than impossible-here. - mobile-auto-test-prompt.md: stand-it-up-here is now the preferred option. - testing-shape.md: mxcli run --local flag table, runtime.log note. - e2e-harness-base.md: BASE_URL no longer assumes localhost:8080. Co-Authored-By: Claude Opus 5 (1M context) --- commands/mobile-auto-test-prompt.md | 25 +++++++++++---- commands/mobile-dev-loop-prompt.md | 50 ++++++++++++++++------------- skills/e2e-harness-base.md | 7 ++-- skills/testing-shape.md | 20 ++++++++++++ 4 files changed, 71 insertions(+), 31 deletions(-) diff --git a/commands/mobile-auto-test-prompt.md b/commands/mobile-auto-test-prompt.md index bafe63a..9834910 100644 --- a/commands/mobile-auto-test-prompt.md +++ b/commands/mobile-auto-test-prompt.md @@ -14,6 +14,14 @@ it has no filesystem in common with your laptop and cannot reach `localhost` on exists so that gap gets stated up front, once, instead of being rediscovered as a confusing `fault` deep into a run. +**Updated 2026-08-21 — the container can now stand the app up itself.** This file used to present +a laptop-hosted app plus a hand-rolled ngrok/cloudflared tunnel as the only options. It is no +longer the shortest path: given the project's repo, this session can run the app locally with +`mxcli docker run` or `mxcli run --local`, and publish it with `mxcli run --local --hub` (a public +URL via `mxcli tunnel-hub`, with `ApplicationRootUrl` set correctly for that origin). Option (c) +below is now the default; (a) and (b) remain valid when you specifically want to test an app +instance that already exists elsewhere. + --- ``` @@ -28,12 +36,17 @@ Setup (do this first, in order): 2. From the toolkit clone, run `bin/doctor.sh` and fix anything it reports missing before continuing — it names exactly what's absent (Python, mxcli binary, etc.) and how to get it. 3. This app must be RUNNING and reachable from this container, plus its database reachable - for OQL/DB assertions. This container cannot reach a laptop's localhost. Either: - (a) it's deployed at a reachable URL — set APP_URL to that, and PG_HOST/PG_PORT (or the - M2EE admin port) to the reachable DB, or - (b) tunnel the local instance out (ngrok/cloudflared) and set APP_URL/PG_HOST to the - tunnel address: . - If neither is possible, stop and say so rather than guessing — a runtime instrument that + for OQL/DB assertions. This container cannot reach a laptop's localhost. In order of + preference: + (c) **stand it up here** — `mxcli docker run -p .mpr --wait`, or `mxcli run --local` + for a Docker-free warm loop (needs JDK 21 and a reachable PostgreSQL whose database + already exists). Add `--hub` if I need to click through it from a browser myself. + Verify with `mxcli docker status`; never infer "up" from the absence of an error. + (a) it's already deployed at a reachable URL — set APP_URL to that, and PG_HOST/PG_PORT (or + the M2EE admin port) to the reachable DB, or + (b) tunnel an existing local instance out and set APP_URL/PG_HOST to the tunnel address: + . + If none is possible, stop and say so rather than guessing — a runtime instrument that can't reach the app should report `fault`/`INVALID`, never be skipped silently or faked green. Skill to follow: skills/existing-app-assurance.md — Track B (Regression / e2e test net). diff --git a/commands/mobile-dev-loop-prompt.md b/commands/mobile-dev-loop-prompt.md index 887c9f1..77199dd 100644 --- a/commands/mobile-dev-loop-prompt.md +++ b/commands/mobile-dev-loop-prompt.md @@ -1,25 +1,30 @@ --- -description: Self-contained prompt to paste into a fresh Claude Code (mobile/cloud) session to run the drafting/static-check half of iterative-build-loop.md — it stops at the Studio Pro-dependent gate rather than faking it +description: Self-contained prompt to paste into a fresh Claude Code (mobile/cloud) session to run the drafting/static-check half of iterative-build-loop.md against an existing project repo --- Copy everything below the line into a new Claude Code session that has no access to your local machine. Fill in the `<...>` blanks first. -**Why this is scoped the way it is:** unlike a pure e2e test run, the build loop's gate needs -**Studio Pro** — a Windows/macOS GUI app — open and reachable at several mandatory points (close -SP → exec → mxbuild gate → reopen SP → Run Locally). The toolkit's own SP automation -(`save-sp.sh`, `restart-sp.sh`) is macOS-only (`osascript`/`lsof`/`open -a`). A headless cloud -container cannot drive a GUI app it has no display for, and there is no tunnel-equivalent fix for -that the way there is for a running web app. So this prompt deliberately does the half of the -loop that has no GUI dependency, and stops cleanly at the handoff instead of pretending to -complete the rest. +**Why this is scoped the way it is.** This prompt is the *drafting* half of the build loop, for +when you want MDL written and statically checked against a project repo without standing up a +runtime. That is a scope choice, not a platform limit. + +> **Correction, 2026-08-21 — this file previously claimed the build gate requires Studio Pro. It +> does not, and that claim blocked cloud sessions at a boundary that isn't real.** The gate is +> `mxbuild`, a plain binary that `project-bin/exec.sh` invokes directly; `exec.sh`'s only Studio +> Pro coupling is a *lock check* (refuse to write while SP holds the `.mpr`), which is a no-op +> where no SP exists. `mxcli new` creates a project headlessly, `mxcli docker run` or +> `mxcli run --local` runs it, `mxcli run --hub` exposes it at a public URL, and +> `mxcli playwright` / `mxcli oql` / `mxcli test --local` exercise it. A container can run the +> whole loop. For the full headless build-and-prove run, use the full-e2e cloud prompt in +> `personal-toolkit/prompts/` instead of this one. --- ``` This is a fresh Claude Code session with no prior context. Task: draft and static-check the next -phase of a Mendix build plan, using mxcli-project-toolkit's iterative-build-loop.md — WITHOUT -Studio Pro, which this session cannot reach. +phase of a Mendix build plan, using mxcli-project-toolkit's iterative-build-loop.md. Scope is +deliberately static: MDL drafted and applied, model-side checks run, no runtime stood up. Setup (do this first, in order): 1. Add and clone these repos: @@ -27,9 +32,9 @@ Setup (do this first, in order): - https://github.com/mendixlabs/mxcli.git (the mxcli CLI — build/install it) - (contains the .mpr this session will read/write against) -2. From the toolkit clone, run `bin/doctor.sh `. It will (correctly) warn that - Studio Pro automation is unavailable here — that's expected, not a problem to fix. Everything - else it reports missing, fix before continuing. +2. From the toolkit clone, run `bin/doctor.sh `. A warning that Studio Pro + automation is unavailable is expected here and is not a problem to fix — nothing in this + prompt's scope uses it. Everything else it reports missing, fix before continuing. 3. Confirm no live Studio Pro elsewhere holds a lock on this project's .mpr (check for a `*.mpr.lock` file, or ask me). mxcli must never touch a .mpr while Studio Pro has it open, including reads — if uncertain, stop and ask rather than risk corrupting the model. @@ -51,20 +56,19 @@ Scope — run through "The Build Loop" steps 1-9 ONLY, then stop: - project-bin/graph-sweep.sh --module - project-bin/coverage-check.sh, against the module's coverage ledger -DO NOT attempt, and do not report as done — hand these back to me explicitly instead: -- Gate: BUILD (bin/exec.sh's mxbuild run + snapshot/auto-restore) — exec.sh's SP handling - requires a live, reachable Studio Pro. -- Reopening Studio Pro, "Update security", or any Cmd+S save. +OUT OF SCOPE for this prompt — do not attempt, and hand these back to me explicitly instead. +These are excluded because this run is deliberately static, NOT because they are impossible here: +- Gate: BUILD (project-bin/exec.sh's mxbuild run + snapshot/auto-restore). Runs fine headless; + it is out of scope only because nothing here stands up a runtime to prove the result. - Gate: UI (module-review.md's PROVE/LOOK stages, project-bin/verify-module.sh, the happy-path - walk) — these need a running app + reachable DB, same as the e2e test prompt - (commands/mobile-auto-test-prompt.md) requires, and this session has neither by default. + walk) — these need a running app + reachable DB, which this prompt does not set up. - Renaming any script to its `done-` prefix — that rename only happens after the FULL gate - (mxbuild + SP reopen + happy-path) passes, which this session cannot verify. + (mxbuild + happy-path) passes, which this session does not verify. Deliverable: the drafted/applied MDL for this phase, syntax-clean per step 6, plus the results of the four static instruments in step 7, plus a short handoff note listing exactly what's left -(mxbuild gate, SP reopen, happy-path walk, module-review.md, done- rename) for me to run locally -or in a session that can reach Studio Pro / the running app. +(mxbuild gate, happy-path walk, module-review.md, done- rename) for me to run in a session that +stands up the app. If you hit anything requiring a judgement call outside this scope (an ambiguous CE error, a requirements gap, whether to touch a shared module), stop and ask rather than guessing — same diff --git a/skills/e2e-harness-base.md b/skills/e2e-harness-base.md index a501eff..946aed9 100644 --- a/skills/e2e-harness-base.md +++ b/skills/e2e-harness-base.md @@ -18,7 +18,8 @@ Build after completing a module build phase: set of idempotent seed SQL scripts run directly against Postgres. See "Seed-data bootstrap" below — the DB smoke check is now expected to self-heal a missing/fresh case rather than just fault the harness on it. -- App running locally (`mxcli docker run -p App.mpr --wait`) +- App running locally (`mxcli docker run -p App.mpr --wait`, or `mxcli run --local` for a + Docker-free warm loop — see `testing-shape.md` for the flag table) --- @@ -27,7 +28,9 @@ Build after completing a module build phase: - Node.js available - Playwright installed: `npm init -y && npm i -D playwright` - `npx playwright install chromium` -- App running at `http://localhost:8080` +- App running at `http://localhost:8080` — or, when this session cannot reach that host (a + cloud container, a devcontainer, a phone), at the public URL from `mxcli run --local --hub`. + Point the harness `BASE_URL` at whichever one actually answers; never assume `localhost:8080`. - A working data-assertion instrument. **Prefer the M2EE admin API** (`mxcli oql --direct`, `adminPort = runtime port + 10`, token from the project's own m2ee config) — see `learned-db-assertions.md`. The `psql.exe` config further down is the Windows-only diff --git a/skills/testing-shape.md b/skills/testing-shape.md index 174df79..e11e0ad 100644 --- a/skills/testing-shape.md +++ b/skills/testing-shape.md @@ -300,6 +300,26 @@ and only report a blocker if you cannot. | `mxcli docker reload` | rebuild + hot reload after an exec | | `mxcli docker down` | tear down | +**Docker-free alternative — `mxcli run --local`.** Keeps an `mxbuild --serve` process and a +standalone Mendix runtime hot: cold first build ~10-15s, then an incremental rebuild ~1s that is +hot-applied without a restart for page/microflow/text changes (entity, view and association changes +still restart the runtime — the metamodel is reconciled only at startup). Needs Mendix 11.x, JDK 21, +and a reachable PostgreSQL whose database **already exists**; no Docker daemon. Runtime stack traces +and microflow `LOG` output land in `/.mxcli/runtime.log` — the browser only shows a +generic dialog, so that file is where a server-side error is actually readable. + +| Flag | Use | +|---|---| +| `--watch` | rebuild and hot-apply on every model change | +| `--hub` | expose the running app at a public URL through `mxcli tunnel-hub` — a chisel client reverse-tunnels out over 443 and the runtime boots with `ApplicationRootUrl` set to the hub URL, so the app works under that origin. Implies `--local`. | +| `--test-endpoint` | host mxcli's token-guarded test endpoint, so `mxcli test -p --attach` runs against this already-warm app — a couple of seconds instead of ~30 | + +**`--hub` is what makes a container-hosted run reachable.** A cloud/devcontainer session has no +shared filesystem with a laptop and cannot serve `localhost` to one. Before `--hub` the only answer +was a hand-rolled ngrok/cloudflared tunnel; it is now a flag. `mxcli test --local` likewise boots on +mxcli's own runtime (ports 8081/8091, its own `_test` database), so a warm `run --local` +loop can keep serving while tests run. + > ### 🔴 Docker is NOT a safe default if the app calls host services by `localhost` > > **Confirmed the hard way, 2026-08-06, on the first real run of this skill.** Inside a container, From 74855687474a28c44cb2b9e7f377c9f077c7c735 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 8 Sep 2026 04:22:00 +0000 Subject: [PATCH 2/2] Salvage the Mac parking branch: existing-app-change skill, v0.20.0 workflow re-probe, BUG-140 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hand-ported from wip/local-divergence-20260901 (7cd08ca) onto current master — only what a prior review found worth keeping, reconciled against what master has learned since: - skills/existing-app-change.md, new: the fourth entry mode (change a live app with no BRDs); routed ba,architect / P,0 / ondemand / spine, surfaces re-rendered; existing-app-assurance.md points here for "change the app you just audited". - learned-workflow-patterns.md §21 (v0.20.0 re-probe) plus the header pointer, the §8 version- table row, §10 step 5 and Notes on scope. DECISION recorded as DISPUTED, not cleared: the toolkit's own same-day retest reproduced BUG-76 byte for byte with `decision '1 = 1'`. CE6681 now attributed to both causes (forward jump per workflow-structure-rules.md, and the self-referencing dangling jump). - learned-mdl-preflight.md STOP #24 (JUMP TO target validation); WITH-clause gotcha stamped v0.16.0-only. - bug-logs: BUG-140 (top-level dataview parameterized microflow datasource never wired on full regen) — number assigned at merge, clear of the 127+ block in flight elsewhere. The branch's BUG-97/98/99 were master's BUG-118/109/110: addenda under those, not new entries. "Cleared on v0.20.0" section added with BUG-76 marked disputed; a matching note under BUG-76. - checkpoints: all three stale project-profile.md references → PROJECT.md (the architecture one was not on the branch; found by grep). - CLAUDE.md: the two-suites testing note, checked still accurate against tests/. Not ported: docs/progress/*, the .gitignore change, and everything master already carried (bin/sync-project.sh, project-bin/verify-module.sh, project-tests/e2e/design-audit.js, workflow-patterns §14–20). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw --- CHANGELOG.md | 7 + CLAUDE.md | 7 + README.md | 1 + ROUTING.md | 1 + agents/architect-agent.md | 1 + agents/ba-agent.md | 1 + bin/gate-check.sh | 4 +- bin/lib/skill-routing.tsv | 1 + bug-logs/mxcli-bugs.md | 157 +++++++++++++++ skills/checkpoints/checkpoint-architecture.md | 2 +- skills/checkpoints/checkpoint-design.md | 7 +- skills/checkpoints/checkpoint-scope.md | 2 +- skills/existing-app-assurance.md | 9 +- skills/existing-app-change.md | 179 ++++++++++++++++++ skills/learned-mdl-preflight.md | 3 +- skills/learned-workflow-patterns.md | 151 ++++++++++++++- 16 files changed, 511 insertions(+), 22 deletions(-) create mode 100644 skills/existing-app-change.md diff --git a/CHANGELOG.md b/CHANGELOG.md index edb4e5b..171e0d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ Kinds: `new` · `fix` · `learn` (a skill/learning) · `process` (rules, templat Credit the person or project that surfaced the change — the credit line is the thank-you. ## 2026-09-08 +- fix(commands): `mobile-dev-loop-prompt.md` no longer claims the build gate needs Studio Pro — the gate is `mxbuild`, a plain binary `exec.sh` invokes directly, and its only Studio Pro coupling is the `.mpr` lock check, a no-op where no Studio Pro exists; both mobile prompts, `testing-shape.md` and `e2e-harness-base.md` now know `mxcli run --local / --hub / --test-endpoint`, so a container stands the app up itself and publishes it at a public URL instead of hand-rolling a tunnel, and the harness `BASE_URL` no longer assumes `localhost:8080` (cherry-pick of 372e2ac, consistent with the cloud lane in `cloud-dev-environment.md` and the runbook's "Where you run this") — Maurits Visser's Mac parking branch, salvaged by the toolkit merge queue +- new(skills/existing-app-change.md): the entry mode the three existing ones did not cover — changing a live Mendix app that has no BRDs, no architecture document and no wireframes. The knowledge base comes from the model itself (**Path D**, `SHOW`/`DESCRIBE`, which cannot silently return zero the way a code extractor does), stages 2–4 run over the changed slice plus its **blast radius** (associations, writers, bound pages, module tangles, published services — the Stage 0 question with no equivalent elsewhere), the Track B regression baseline is the precondition rather than an option, every gate from Stage 5 on is also a regression gate, and the ledger denominator is the slice's leaves, said out loud. Routed as `ba,architect / P,0 / ondemand / spine`; `existing-app-assurance.md` now points here instead of back at the runbook — Maurits Visser's Mac parking branch, salvaged by the toolkit merge queue +- learn(workflow): `learned-workflow-patterns.md` §21 — a full v0.20.0 re-probe (2026-08-31, Mendix 11.13.0) rebuilt a 23-activity BPM-engine conversion workflow from pure MDL at 0 native errors: non-interrupting boundary timer and `wait for timer` cleared, `$Type` re-confirmed fixed, `DESCRIBE WORKFLOW` reads decisions/jumps/waits/boundary events back, `create or replace workflow` now refuses to delete an Event Sub-Process; four gaps remain (Event Sub-Process, End activities, body annotations, a three-fix `describe → exec` loop) and the `JUMP TO` trap is spelled out — mxcli names activities after the called microflow, a dangling target is stored as a self-reference, and `CE6681` names the wrong fault. Merged against master's newer state: the `DECISION` result is recorded as **disputed**, not cleared, because the toolkit's own same-day retest reproduced BUG-76 byte for byte with `decision '1 = 1'`; §8's version table, §10 step 5 and the Notes on scope updated accordingly — Maurits Visser's Mac parking branch, salvaged by the toolkit merge queue +- learn(preflight): STOP #24 — a `JUMP TO` target must be a real activity name and mxcli will not check it (passes `check --references` and `exec`, stored as a jump pointing at itself, `CE6681` at native check; `DESCRIBE` output walks you into it); the v0.16.0 `WITH`-clause gotcha is stamped as v0.16.0-only after 14/14 calls stored correctly on v0.20.0 — Maurits Visser's Mac parking branch, salvaged by the toolkit merge queue +- new(bug-logs): BUG-140 — a full page regeneration never wires a parameterized microflow datasource on a top-level `dataview` (CE1571 on 15 of 15 pages, even byte-identical to a working original; explicit `Params:` is accepted and dropped, enum literals are rejected outright); only implicit binding through one level of nesting works, proven on a throwaway page. Number 140 assigned at merge, clear of the 127+ block another branch was taking. Plus addenda where the branch's findings matched existing entries instead of new numbers: BUG-109 gets the general dangling-`jump to` case and its upstream issue #1005, BUG-110 its #1006 link and the second emitter defect #1007 (`annotation` statements `MDL-WF04` rejects), BUG-118 an earlier v0.18.0 two-entry `ContentParams` observation from a second project and the full-page-rewrite workaround; a "Cleared on v0.20.0" section records the workflow re-probe, with BUG-76 marked disputed against the same-day retest — Maurits Visser's Mac parking branch, salvaged by the toolkit merge queue +- fix(checkpoints): the last three `project-profile.md` references — a file no project has — now point at `PROJECT.md` → `## Decisions` (`checkpoint-design.md` Figma/brand answers, `checkpoint-scope.md` external refs, `checkpoint-architecture.md` NFRs; the third was not on the branch, found by grep at merge) — Maurits Visser's Mac parking branch, salvaged by the toolkit merge queue +- process(CLAUDE.md): "Testing this toolkit" now says there are two suites — `tests/run-tests.sh` is self-contained, each `tests/wave2/test-*.sh` takes its subject as `$1` and several take something other than `gate-check.sh` — so a permitted single-fixture run is invoked correctly the first time (checked still accurate: 24 fixtures, `run-all.sh` resolves the subject from the same `usage:` line) — Maurits Visser's Mac parking branch, salvaged by the toolkit merge queue - process(bug-logs): filed the BUG-120..126 harvest upstream — #1067 (write-path asymmetries), #1068 (parallel split writes paths without contents), #1069 (`ALTER PAGE SET PageSize`, citing #414 as the general case), #1070 (`DESCRIBE MICROFLOW` omits `without events`), #1071 (`check --references` cannot resolve enumerations). Dedupe redirected two: BUG-126 is mendixlabs/mxcli#292, open since April and the same bug, and BUG-123 is #773, closed as completed 2026-08-12 and still reproducing — both posted as reproductions on the existing issues rather than re-filed. Every draft carried a Mendix version but no mxcli version; v0.20.0 (from `mxcli-bugs.md`) is now in each Environment section, in the drafts as well as upstream. BUG-117 stays held pending its v0.20.0 retest, BUG-118 pending BUG-114 having an upstream issue at all — it has none — Maurits Visser, via the toolkit merge queue ## 2026-09-07 diff --git a/CLAUDE.md b/CLAUDE.md index 02550ba..6076fd5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -250,6 +250,13 @@ changed `bin/gate-check.sh` → also run `test-bug03-gates.sh`, `test-source-suf whatever else targets it). Grep `tests/wave2/` for the filename you changed if you're unsure which fixtures cover it. +There are two separate suites. `tests/run-tests.sh [-v]` is self-contained (guard-script +fixtures with no external argument). Each `tests/wave2/test-*.sh` fixture instead takes its +subject-under-test as `$1` — read its own `usage:` comment rather than assuming a fixed target; +several take something other than `gate-check.sh` (`exec.sh`, `sync-project.sh`, +`check-docs-numbering.sh`, a skill file). Once you have permission for a single fixture (see +below), run it as e.g. `bash tests/wave2/test-bug02-register.sh bin/gate-check.sh`. + **Why:** this repo is routinely edited by more than one agent session at once (real incident, 2026-08-19 — a peer session mid-edit reported known, unrelated failures already present in the shared working tree). A full-suite run over a moving target mixes someone else's in-flight diff --git a/README.md b/README.md index ef27f72..b6cab6b 100644 --- a/README.md +++ b/README.md @@ -494,6 +494,7 @@ Every mxcli project has a `.ai-context/skills/` directory (bundled by `mxcli ini | CAC-6, after Stage 6 passes and before any cutover step — migration mode only, and a hard gate: every answer lands CONFIRMED, no ASSUMED defaults | `skills/checkpoints/checkpoint-cutover.md` | | Generating a new project's CLAUDE.md — baseline routing plus project-specific facts | `skills/bootstrap-project.md` | | Setting up or resuming an mxcli project in a cloud/ephemeral container — the one-time setup order (mxcli download → mxcli init → init-project.sh → sources decision → push) and the commit-and-push loop that survives container reclaim | `skills/cloud-dev-environment.md` | +| Changing an EXISTING Mendix app — adding a feature, altering a flow, restructuring a module — when it has no BRDs, no architecture doc and no wireframes: the knowledge base comes from the live model (Path D), stages 2–4 run over the changed slice plus its blast radius only, and the Track B regression baseline is the precondition; audit-only stays in existing-app-assurance | `skills/existing-app-change.md` | | Cutover and retrospective — promoting proven patterns back into the toolkit | `skills/close-the-loop.md` | | Before citing ANY behavioural claim about the harness, the Mendix runtime or a test tool as evidence — a claim not in the register may not be cited | `skills/measured-claims.md` | | Any review pass that runs more than once — module-review, coherence, monkey, wiring-sweep: findings accumulate across runs, a per-run report cannot show a trend | `skills/improvement-register.md` | diff --git a/ROUTING.md b/ROUTING.md index 804aa31..99ea775 100644 --- a/ROUTING.md +++ b/ROUTING.md @@ -50,6 +50,7 @@ picks the row up. That is the whole procedure — there is no second list to rem | Deciding who answers a question — before putting any batch to the user. gap/conflict/choice/user-only is what keeps a gate batch at four questions instead of 127 | `bin/question-kinds.sh` | ba | 1,2,3 | baseline | | Generating a new project's CLAUDE.md — baseline routing plus project-specific facts | `skills/bootstrap-project.md` | ba | P | ondemand | | Setting up or resuming an mxcli project in a cloud/ephemeral container — the one-time setup order (mxcli download → mxcli init → init-project.sh → sources decision → push) and the commit-and-push loop that survives container reclaim | `skills/cloud-dev-environment.md` | all | P | ondemand | +| Changing an EXISTING Mendix app — adding a feature, altering a flow, restructuring a module — when it has no BRDs, no architecture doc and no wireframes: the knowledge base comes from the live model (Path D), stages 2–4 run over the changed slice plus its blast radius only, and the Track B regression baseline is the precondition; audit-only stays in existing-app-assurance | `skills/existing-app-change.md` | ba,architect | P,0 | ondemand | | Cutover and retrospective — promoting proven patterns back into the toolkit | `skills/close-the-loop.md` | all | 7 | ondemand | | Before citing ANY behavioural claim about the harness, the Mendix runtime or a test tool as evidence — a claim not in the register may not be cited | `skills/measured-claims.md` | all | - | ondemand | | Any review pass that runs more than once — module-review, coherence, monkey, wiring-sweep: findings accumulate across runs, a per-run report cannot show a trend | `skills/improvement-register.md` | mdl,gate,test,review | 5,6 | ondemand | diff --git a/agents/architect-agent.md b/agents/architect-agent.md index 67d188f..3de9fe7 100644 --- a/agents/architect-agent.md +++ b/agents/architect-agent.md @@ -46,6 +46,7 @@ You own architecture and build-plan decisions for {{PROJECT}}. Hard rule: you ne | `skills/checkpoints/checkpoint-build.md` | CAC-5, after design sign-off and before the build plan — build order and slice boundaries. Opens with a brainstorm | | `project-bin/check-design-portability.sh` | Before porting ds.css into SCSS, and at the Stage-3 gate — greps the stylesheet for rules that cannot match the HTML Mendix emits (rem against the real root, table/th/td selectors, positional row selectors). mx check, mxcli check and mxcli lint are all blind to CSS | | `skills/cloud-dev-environment.md` | Setting up or resuming an mxcli project in a cloud/ephemeral container — the one-time setup order (mxcli download → mxcli init → init-project.sh → sources decision → push) and the commit-and-push loop that survives container reclaim | +| `skills/existing-app-change.md` | Changing an EXISTING Mendix app — adding a feature, altering a flow, restructuring a module — when it has no BRDs, no architecture doc and no wireframes: the knowledge base comes from the live model (Path D), stages 2–4 run over the changed slice plus its blast radius only, and the Track B regression baseline is the precondition; audit-only stays in existing-app-assurance | | `skills/architecture-blueprint.md` | Diagramming target architecture — module defs, wiring, fit-gap, marketplace, security, NFRs, integrations | | `skills/modularize-domain.md` | Deciding module boundaries before "create module" | | `skills/design-artifacts.md` | Designing the brand and ONE ANNOTATED WIREFRAME PER SCREEN before building pages — the design system alone is half the deliverable | diff --git a/agents/ba-agent.md b/agents/ba-agent.md index fdd354b..dd52bda 100644 --- a/agents/ba-agent.md +++ b/agents/ba-agent.md @@ -58,6 +58,7 @@ You run discovery and the interview gates for {{PROJECT}}. You never touch the ` | `bin/brd-report.sh` | Reviewing what the BRDs actually say — the Stage 2 surface, for BRDs from any source. Reads every knowledge base at once, and keeps a section that is absent-because-not-applicable apart from one that is absent-because-expected | | `skills/bootstrap-project.md` | Generating a new project's CLAUDE.md — baseline routing plus project-specific facts | | `skills/cloud-dev-environment.md` | Setting up or resuming an mxcli project in a cloud/ephemeral container — the one-time setup order (mxcli download → mxcli init → init-project.sh → sources decision → push) and the commit-and-push loop that survives container reclaim | +| `skills/existing-app-change.md` | Changing an EXISTING Mendix app — adding a feature, altering a flow, restructuring a module — when it has no BRDs, no architecture doc and no wireframes: the knowledge base comes from the live model (Path D), stages 2–4 run over the changed slice plus its blast radius only, and the Track B regression baseline is the precondition; audit-only stays in existing-app-assurance | | `skills/assess-migration.md` | Assessing or planning a migration up front, before any pipeline is chosen | | `skills/migration-pipeline.md` | Running the extraction pipeline | | `skills/migrate-general.md` | Migrating from a stack that has no dedicated pipeline | diff --git a/bin/gate-check.sh b/bin/gate-check.sh index 96eb224..137c4ed 100755 --- a/bin/gate-check.sh +++ b/bin/gate-check.sh @@ -1441,8 +1441,8 @@ stage_protocol_paths() { # every stage as "(unmapped)" — noisy by design, but only after someone hits it. case "$1" in # - P) echo "skills/interview-protocol.md skills/grill-mode.md skills/agent-roles.md skills/bootstrap-project.md skills/cloud-dev-environment.md skills/mendix-epics-api.md skills/corpus-extraction-integrity.md skills/platform-link.md" ;; - 0) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-scope.md skills/source-triage.md skills/assess-migration.md skills/migration-pipeline.md skills/migrate-general.md skills/migrate-outsystems.md skills/source-os11.md skills/os-xml-schema.md skills/source-node-express-react.md skills/document-discovery.md skills/extractor-quality-loop.md skills/qa-loop-goal-pattern.md skills/mendix-epics-api.md skills/corpus-extraction-integrity.md skills/gate-check-file-locations.md" ;; + P) echo "skills/interview-protocol.md skills/grill-mode.md skills/agent-roles.md skills/bootstrap-project.md skills/cloud-dev-environment.md skills/existing-app-change.md skills/mendix-epics-api.md skills/corpus-extraction-integrity.md skills/platform-link.md" ;; + 0) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-scope.md skills/source-triage.md skills/existing-app-change.md skills/assess-migration.md skills/migration-pipeline.md skills/migrate-general.md skills/migrate-outsystems.md skills/source-os11.md skills/os-xml-schema.md skills/source-node-express-react.md skills/document-discovery.md skills/extractor-quality-loop.md skills/qa-loop-goal-pattern.md skills/mendix-epics-api.md skills/corpus-extraction-integrity.md skills/gate-check-file-locations.md" ;; 1) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-extraction.md skills/migration-pipeline.md skills/source-os11.md skills/os-xml-schema.md skills/source-node-express-react.md skills/document-discovery.md skills/extractor-quality-loop.md skills/kb-generation.md skills/corpus-extraction-integrity.md" ;; 2) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-brd.md skills/checkpoints/checkpoint-architecture.md skills/kb-generation.md skills/brd-generation.md skills/brd-validation.md" ;; 3) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-design.md skills/architecture-blueprint.md skills/modularize-domain.md skills/design-artifacts.md skills/brd-to-build-plan.md skills/workflow-structure-rules.md skills/learned-mdl-cannot-express.md" ;; diff --git a/bin/lib/skill-routing.tsv b/bin/lib/skill-routing.tsv index b5564de..91f3930 100644 --- a/bin/lib/skill-routing.tsv +++ b/bin/lib/skill-routing.tsv @@ -100,6 +100,7 @@ mxcli-bugs bug-logs/mxcli-bugs.md A CE error or behavior that looks like a known bootstrap-project skills/bootstrap-project.md Generating a new project's CLAUDE.md — baseline routing plus project-specific facts ba P ondemand spine cloud-dev-environment skills/cloud-dev-environment.md Setting up or resuming an mxcli project in a cloud/ephemeral container — the one-time setup order (mxcli download → mxcli init → init-project.sh → sources decision → push) and the commit-and-push loop that survives container reclaim all P ondemand spine existing-app-assurance skills/existing-app-assurance.md Auditing or regression/e2e-testing an EXISTING app — no intake, no stages, no gates test,review 6 ondemand verify +existing-app-change skills/existing-app-change.md Changing an EXISTING Mendix app — adding a feature, altering a flow, restructuring a module — when it has no BRDs, no architecture doc and no wireframes: the knowledge base comes from the live model (Path D), stages 2–4 run over the changed slice plus its blast radius only, and the Track B regression baseline is the precondition; audit-only stays in existing-app-assurance ba,architect P,0 ondemand spine assess-migration skills/assess-migration.md Assessing or planning a migration up front, before any pipeline is chosen ba 0 ondemand source migration-pipeline skills/migration-pipeline.md Running the extraction pipeline ba 0,1 ondemand source migrate-general skills/migrate-general.md Migrating from a stack that has no dedicated pipeline ba 0 ondemand source diff --git a/bug-logs/mxcli-bugs.md b/bug-logs/mxcli-bugs.md index 3130ab5..42cef1a 100644 --- a/bug-logs/mxcli-bugs.md +++ b/bug-logs/mxcli-bugs.md @@ -2744,6 +2744,15 @@ before touching the live one. > **CONFIRMED STILL OPEN on v0.20.0 — CRITICAL, verified 2026-08-31 with the byte-exact original signature: `StorageLoadException … The text 'OutcomeA' is not a valid EnumerationValueIdentifier`, project unloadable by mxbuild. Keep the STOP rule: no DECISION activities in CREATE WORKFLOW via mxcli.** See [mxlabs-v0.20.0-retest-2026-08-31.md](mxlabs-v0.20.0-retest-2026-08-31.md). +> **Contradicting evidence, same day (2026-08-31, v0.20.0, Mendix 11.13.0):** a separate probe rebuilt a +> real 23-activity workflow containing one `DECISION` from pure MDL and it **loaded natively at 0 +> errors** (`ExclusiveSplitActivity` stored, `learned-workflow-patterns.md` §21). That probe did not +> record the decision's expression/outcome shape, while the retest above used `decision '1 = 1'` with +> fresh outcome labels. Two v0.20.0 probes, opposite verdicts → the defect is **shape-dependent and +> not isolated**. The STOP rule stays; the next person with a v0.20.0 binary should bisect the shape +> (typed-attribute expression vs literal; outcome labels that match an enumeration vs invented ones). +> See "Cleared on v0.20.0" at the end of this file. + **Project:** PROJECT-A, Phase 15 (Approval native Workflow build), script 65 (`Approval.ApprovalWorkflow`). **mxcli version:** v0.17.0 (`2026-08-10T05:12:17Z`). @@ -3867,6 +3876,23 @@ expressed correctly in MDL. Mendix requires its path to end in *End workflow* or `END OF BOUNDARY EVENT PATH` are all parse errors as statements, and `JUMP TO` is this bug. Non-interrupting boundary events are unaffected and work correctly. +**Also observed — the general case, 2026-08-31, v0.20.0 (`2026-08-28T13:22:53Z`), Mendix +11.13.0, filed as [mxcli#1005](https://github.com/mendixlabs/mxcli/issues/1005):** a +`jump to X` whose `X` matches **no activity at all** — anywhere in the body, not only inside a +boundary event — passes `check --references` and `exec`, and is stored as a `JumpToActivity` +whose own `Name` is `X` with `TargetActivity` also `X`: a jump targeting itself. Native +`mx check` then reports `CE6681 "It is not possible to jump to end activities or jump-to +activities."` — the wrong fault (jump legality) for the real one (unresolved reference); the +same code is Mendix's genuine verdict on a *forward* jump (`workflow-structure-rules.md`), so +check the target exists before reasoning about direction. Write-path, confirmed by `strings -n 3` +on the stored `.mxunit`, not by `DESCRIBE`. It is easy to hit because **mxcli names a +call-microflow activity after the microflow it calls** (`SUB_CheckPackageAvailability`, never +`callMicroflow6`), the grammar cannot name one explicitly, and `DESCRIBE WORKFLOW` emits jump +targets using the *source* model's names — so `describe → exec` reliably produces a dangling +target. Workaround: repoint every `jump to` at a real activity name before exec and gate on +native `mx check`; `learned-mdl-preflight.md` STOP #24. Same entry, two shapes — do not file +the general case separately from #1005. + --- ## BUG-110: `DESCRIBE WORKFLOW` emits MDL it cannot re-parse when a targeting XPath contains quotes @@ -3899,6 +3925,19 @@ Feeding that back to `mxcli check` fails: current state before editing (`query-the-model.md`), so this silently produces a script that looks authoritative and cannot run. +**Filed:** [mxcli#1006](https://github.com/mendixlabs/mxcli/issues/1006) (2026-08-31, from an +earlier v0.20.0 / Mendix 11.13.0 observation of the same emitter defect — the draft in +`pending-github-issues/` already records the dedupe). **Also observed, same probe, second +emitter defect filed separately as [mxcli#1007](https://github.com/mendixlabs/mxcli/issues/1007) +because the fix lives elsewhere:** `DESCRIBE WORKFLOW` emits canvas annotations as `annotation` +statements that mxcli's own checker rejects with `MDL-WF04` — a real 23-activity workflow +produced 13 of them from unmodified describe output. Requested fix: emit them as MDL comments, +which is MDL-WF04's own remediation advice. Same family as #619 (unquoted reserved-word +identifiers) and #978 (`DESCRIBE PAGE` rejected by mxcli's own check) — the emitter is not held +to the parser's grammar by any test. Practical consequence: `describe → exec` needs three hand +fixes before it runs — double the XPath quotes, strip the annotations, repoint the jumps +(BUG-109 / #1005). The ritual is `learned-workflow-patterns.md` §21. + --- ## BUG-111: `mxcli syntax` drill-down rejects the example printed in its own help text @@ -4551,6 +4590,19 @@ template fresh, has correctly-bound ContentParams on its siblings — only a REP GALLERY template), confirmed via a real `mx check` CE0402 build error (not a silent drop — the gate caught it) plus `DESCRIBE PAGE`'s literal `` output. +**Earlier observation of the same defect, 2026-08-21, mxcli v0.18.0, Mendix 11.13.0, an +approval-workflow conversion project (a second project — corroboration, not a duplicate):** a +`REPLACE` inside a gallery template introducing a `dynamictext` with a **two-entry** +`ContentParams: [{1} = Attr1, {2} = Attr2]`, a genuinely distinct widget name (ruling out +BUG-08's duplicate-name case) and bare attribute names (ruling out BUG-23's `$currentObject/` +case) — `check --references` clean, exec "Altered page", `DESCRIBE PAGE` shows both entries +``, native `mx check` CE0402 once per entry. So the defect is not limited to single-entry +arrays, and it predates v0.20.0. Second workaround, for when there is no already-bound widget to +`SET` on: `DESCRIBE PAGE` the whole page, patch only the target widget block, and re-apply it as +`create or replace page` (swap the `create or modify page` keyword describe emits), then gate on +native `mx check` — the full-page writer binds template-scoped `ContentParams` correctly; only the +`REPLACE` path does not. + --- ## BUG-119: the bundled `write-nanoflows.md` skill teaches a `SHOW MESSAGE` grammar the shipped binary rejects, and `mxcli syntax` documents the activity nowhere @@ -5197,3 +5249,108 @@ quietly drop one. **Related:** BUG-122 (`SET PageSize` rejected on a widget `CREATE` accepts). Same underlying theme — the `ALTER PAGE` property surface disagrees with the `CREATE` one — but the failure mode is the opposite and much more dangerous. + +--- + +## BUG-140: full page regeneration never wires a parameterized microflow datasource on a top-level `dataview` — only implicit binding through nesting works + +*(number assigned at merge — 140 taken deliberately, clear of the 127+ block another branch was +numbering the same day)* + +**Severity:** High — silent; `mxcli check --references` and the exec's own "Created page" both pass, only native `mx check` (CE1571) catches it +**mxcli version when found:** v0.18.0 (open as of v0.18.0; not yet retested on v0.20.0) +**Mendix version:** 11.13.0 +**Discovered:** 2026-08-21, an approval-workflow conversion project — 15 native-Workflow "station task" pages, each needing a dataview scoped to a lookup microflow keyed by the page's `WorkflowUserTask` parameter plus a per-page enum literal +**Reproducible:** yes — a full 15-page rebuild without nesting produced `CE1571` on all 15; a disposable throwaway page isolated nesting as the fix + +### Summary + +A `dataview` whose `DataSource: microflow X` requires **any** parameter cannot have that +parameter wired by a full `create or modify page` regeneration, when the dataview is a direct +child of the page body (not nested inside another dataview/snippet). Confirmed even when the +page is reproduced **byte-for-byte identical to its own pre-existing, working original** — no +edits at all — native `mx check` still throws `CE1571 "No argument has been selected for +parameter '...' and no default is available."` for every such parameter. `mxcli check +--references` and the exec's own "Created page ..." success message both stay silent; this is +caught only by a real native `mx check` (or Studio Pro's own error pane). + +### What does NOT fix it + +- Adding an explicit `Params: { Param: $value }` clause on the dataview: `mxcli check` accepts + this syntactically (no error), but the writer still drops the mapping — native check still + fails identically. +- Using an enum literal as a `Params:` value (e.g. `Params: { StationKey: + Approval.StationKey.WFST010 }`): rejected outright by `mxcli check` itself + (`mismatched input 'Approval' expecting VARIABLE`) — `Params:` accepts only `$variable` + references, never literals, on any binding. +- Reducing the microflow to a single parameter, while keeping the dataview a direct child of + the page body: still fails. Parameter *count* is not the variable — nesting is. + +### What does fix it — implicit binding through nesting + +The writer *can* wire a microflow-datasource dataview's parameter, but only when the dataview +is nested one level inside another dataview/snippet whose own current-object type exactly +matches the microflow's sole parameter type, and the inner dataview has **no** `Params:` clause +at all: + +``` +dataview dvOuter (DataSource: $PageParam) { + dataview dvInner (DataSource: microflow Module.SingleParamMicroflow) { + -- $currentObject here is whatever SingleParamMicroflow returns + } +} +``` + +`SingleParamMicroflow` must take exactly one parameter, of the same type as `$PageParam` +(or whatever the outer dataview's current-object type is). If the real business logic needs +more inputs than that one type provides (e.g. an enum literal that varies per page instance), +write a thin single-parameter wrapper microflow that hardcodes the rest internally via a normal +`call microflow` expression — enum literals *are* valid inside a microflow body, just never +inside a page's `Params:` clause. + +Verify the mechanism on a disposable throwaway page first (create it, native `mx check`, then +`DROP PAGE` it) before rolling out to real pages — a clean throwaway page next to N still-broken +real ones in the same `mx check` run isolates the fix from everything else in flight. + +### Relationship to other bugs + +Same failure signature and root category as BUG-95 (`show_page` action ignoring the named +variable, defaulting to `$currentObject`) and the "snippetcall doesn't auto-infer Params on +full regen" / "`ALTER PAGE REPLACE` silently unbinds `Attribute:` shorthand" findings in +`skills/learned-datagrid-customcontent-binding.md` — all are instances of mxcli's writer +silently failing to wire a parameter/argument mapping that Studio Pro's own GUI always forces +the user to complete, while `mxcli check` has no way to see the gap. Distinct from BUG-56 +(DataGrid2 *datasource* parameterized-microflow binding, resolved v0.17.0, archived) — this is a +plain `dataview`, not a DataGrid2 grid. + +### Workaround + +Use the nesting pattern above. Do not attempt a third variation of the `Params:` clause on a +non-nested dataview — the defect is structural (a missing implicit-binding pass for top-level +dataviews), not a syntax problem. + +--- + +## Cleared on v0.20.0 — a workflow re-probe, 2026-08-31 + +**Probed 2026-08-31** on mxcli v0.20.0 (`2026-08-28T13:22:53Z`), Mendix 11.13.0, against a real +23-activity conversion workflow rebuilt from pure MDL in a throwaway clone, gated with native +`mx check` via `mxcli docker check`. Result: **0 errors**. Full write-up: `learned-workflow-patterns.md` +§21. This is a second v0.20.0 data point beside `mxlabs-v0.20.0-retest-2026-08-31.md`, and on one +row the two disagree. + +| Defect | Entry | Status on v0.20.0 | +|---|---|---| +| `DECISION` corrupts the `.mpr` | BUG-76 | **Disputed.** This probe's `ExclusiveSplitActivity` stored and natively loaded; the same-day retest reproduced the byte-exact corruption with `decision '1 = 1'`. Shape not isolated — STOP rule stays (note under BUG-76). | +| MDL-written non-interrupting `BOUNDARY EVENT … TIMER` always malformed (`CE0105`) | a project-local finding, no toolkit entry | **Fixed for the non-interrupting form.** Timer wrote and loaded, reading a context attribute. The interrupting form is still unusable — BUG-109 and `learned-workflow-patterns.md` §19. | +| pre-11.9 `Workflows$CallMicroflowTask` `$Type` | BUG-WF06 (archived, fixed v0.17.0) | **Re-confirmed fixed.** 14/14 stored as `CallMicroflowActivity`. | + +Also new in v0.20.0: `create or replace workflow` now **refuses** when the target contains an +Event Sub-Process ("MDL cannot express one — rewriting the workflow would delete it"), instead +of silently destroying it. Do not read that guard's absence as safety on an older binary. + +Still unfixed: no branch-ending vocabulary — `end workflow activity`, `end activity`, `end`, +`terminate`, `stop`, `end workflow instance` all fail to parse, so End activities on +fall-through outcome arms remain a permanent hand edit (`workflow-structure-rules.md` §11). +Found in the same probe and filed: BUG-109's general dangling-`jump to` case (#1005) and +BUG-110's two emitter defects (#1006, #1007). diff --git a/skills/checkpoints/checkpoint-architecture.md b/skills/checkpoints/checkpoint-architecture.md index 1ae4dc1..9cb8bfe 100644 --- a/skills/checkpoints/checkpoint-architecture.md +++ b/skills/checkpoints/checkpoint-architecture.md @@ -116,7 +116,7 @@ listing which BRDs/features triggered it and the chosen option. > 'must be certified for [standard]'). Drop them here or say 'none for POC.'" **What to do with the answer:** -- Add to `project-profile.md` under `## Non-Functional Requirements` +- Record them in `PROJECT.md` under `## Decisions` as `NFRs:` — one line each, `CONFIRMED` - Flag any that directly affect module structure (e.g. multi-tenancy → affects all XPath constraints) - Note deferred NFRs in `PROJECT.md` so they aren't lost diff --git a/skills/checkpoints/checkpoint-design.md b/skills/checkpoints/checkpoint-design.md index 241b96a..f403b4f 100644 --- a/skills/checkpoints/checkpoint-design.md +++ b/skills/checkpoints/checkpoint-design.md @@ -82,7 +82,7 @@ or desktop-first. Use that to set the recommended option. | Answer type | Action | |---|---| -| Figma link | Add to `project-profile.md` → External References. Note which flows are designed vs wireframe-only. | +| Figma link | Add to `PROJECT.md` → `## Decisions` → `Design assets:`. Note which flows are designed vs wireframe-only. | | Brand doc / PDF | Same as above. Extract: primary color, font family, logo usage rules. | | Verbal description | Record key decisions (primary color, font, tone) in `design-artifacts.md` inputs. | | "Atlas defaults" | Note it. No custom tokens needed. Skip Atlas customization in MDL layer. | @@ -98,8 +98,3 @@ PROJECT.md → ## Decisions: Platform target: [web / responsive / native / both] Design assets: [Figma URL / brand doc link / 'Atlas defaults' / description] ``` - -``` -project-profile.md → ## External References: - Design: [link or 'Atlas defaults'] -``` diff --git a/skills/checkpoints/checkpoint-scope.md b/skills/checkpoints/checkpoint-scope.md index 06ac14a..c230a61 100644 --- a/skills/checkpoints/checkpoint-scope.md +++ b/skills/checkpoints/checkpoint-scope.md @@ -97,7 +97,7 @@ If found: option A = reuse it. If not found: offer build-new vs manual-only. > the target? Drop a link or paste the key constraints — or say 'none' if this is code-only." **What to do with the answer:** -- If a link is provided: add it to `project-profile.md` under `## External References` +- If a link is provided: add it to `PROJECT.md` under `## Decisions` as `External refs:` - If constraints are pasted: record them in `PROJECT.md` under `## Decisions` - If 'none': note it and proceed diff --git a/skills/existing-app-assurance.md b/skills/existing-app-assurance.md index 609b8ac..05e70d6 100644 --- a/skills/existing-app-assurance.md +++ b/skills/existing-app-assurance.md @@ -13,7 +13,14 @@ - Before a Mendix version upgrade or a big refactor: record what the app does *today* so you can prove it still does it afterwards. - You inherited an app and need to understand it before touching it. -Not for building anything new — that's `conversion-runbook.md` (pick an entry mode there). +Not for building anything new. Two different places to go, depending on what "new" means: + +- **Changing the app you just audited** — adding a feature, altering a flow, restructuring a module → + `existing-app-change.md`. That skill starts where this one ends: Track B's baseline is its + precondition, not an optional extra, because an app with no specification has nothing else to be + checked against. +- **Building a different app** — a migration from a non-Mendix source, or a new app → + `conversion-runbook.md` (pick an entry mode there). ## Ground rules diff --git a/skills/existing-app-change.md b/skills/existing-app-change.md new file mode 100644 index 0000000..3960a81 --- /dev/null +++ b/skills/existing-app-change.md @@ -0,0 +1,179 @@ +# Change an Existing App — Adding To or Altering a Mendix App You Already Have + +**Applies to:** any mxcli project — a live Mendix app, built by people, with no BRDs, no architecture +document and no wireframes, that you now need to change. +**Requires:** the app's `.mpr`, a runnable local environment, bash and Python 3. Run `bin/doctor.sh` +once on a new machine. Windows: Git Bash, and see `conversion-runbook.md` → Prerequisites. +**Purpose:** The recipe for changing an app the pipeline never built. The knowledge base comes from +**the model itself**, not from an extractor, and stages 2–4 run over the **slice you are changing** — +not over the whole application. +**Source:** Field run #1, 2026-08-20. The three entry modes all assume the target app does not exist +yet, and the classification rules sent an existing `.mpr` to Migration — i.e. to migrating the app to +itself. `existing-app-assurance.md` covers audit and testing and says in as many words *"not for +building anything new"*, which sent you back to the three modes that did not fit. This file closes +that loop. + +--- + +## When to Use This Skill + +- "Add click-and-collect to our webshop." +- "The approval flow needs a second approver above €250." +- "Replace the CSV export with a real ERP integration." +- "This module is a mess and we want to restructure it" — restructuring is a change like any other. + +**Not this skill:** + +| You want | Go to | +|---|---| +| To understand, audit or lint the app; a regression net; no change planned | `existing-app-assurance.md` | +| To rebuild the app on Mendix from a non-Mendix source | `conversion-runbook.md` → Migration | +| A brand-new app | `conversion-runbook.md` → Requirements-driven or Greenfield | +| A one-line fix you would not open a ticket for | Just do it. This skill is overhead for a typo. | + +The line between "a change" and "a new app inside an old one" is scope, and Stage 0 draws it. If the +slice turns out to be most of the app, you are in Migration mode with a Mendix source — say so and +switch. + +--- + +## Ground rules + +**1. The regression net comes first, and it is not optional.** + +Every other entry mode has a specification to check the result against. This one does not: the app is +its own specification and nobody wrote it down. The substitute is a proven statement of what the app +does *today*, before you touch it — `existing-app-assurance.md` Track B, at minimum over the modules +your change touches. + +Skip it and you have no way to tell a bug you introduced from behaviour that was always like that. +That is the entire risk of this entry mode, concentrated in one decision. + +**2. The slice is the unit of work, not the app.** + +You are not writing BRDs for a five-year-old application. You are writing them for what changes, plus +what that change touches. Everything downstream — the ledger denominator, the coverage claim, the +gates — is scoped to the slice. A coverage number that silently means "of the slice" while reading +like "of the app" is the false-green this toolkit keeps producing; say which one you mean, every time. + +**3. The model is ground truth. Memory and the UI are not.** + +Ask the model, not the app's screens and not the person who thinks they remember. `query-the-model.md` +is baseline routing for a reason, and here it is the primary instrument rather than a convenience. + +**4. Record the as-is before you record the to-be.** + +For each thing you change, write what it does now and what it should do. The as-is half is the piece +that gets skipped and the piece that has no other home — after the change it is unrecoverable except +from git history of a `.mpr`, which is not a readable record. + +--- + +## Where the knowledge base comes from — Path D + +`conversion-runbook.md` Stage 1 names three paths: **A** code → AST extractors, **B** documents → LLM +extraction, **C** SME interview. This entry mode adds a fourth. + +**Path D — the live model.** No extractor, no parsing, no regex. `mxcli` reads the `.mpr` and answers +directly: + +```bash +./mxcli -p .mpr -c "SHOW MODULES" +./mxcli -p .mpr -c "SHOW ENTITIES IN " +./mxcli -p .mpr -c "SHOW ASSOCIATIONS" +./mxcli -p .mpr -c "DESCRIBE ENTITY ." +./mxcli -p .mpr -c "SHOW PAGES IN " +./mxcli -p .mpr -c "SHOW MICROFLOWS IN " +mxcli graph-report # dependency tangles, community detection +``` + +**Path D does not have Path A's failure mode, and that is the main reason this entry mode is safer +than it looks.** A code extractor guesses at files and silently returns zero for a construct class +whose layout it did not anticipate — field run #1 lost 39 Angular components, 35 REST endpoints and +18 SQL tables that way, with every instrument reporting green. The model cannot do this. It either +answers or errors, and `SHOW ENTITIES` is the count, not an estimate of the count. + +Still record the counts. `SHOW MODULES` returning 6 when the person who asked for the change said +"about twenty" is a scope conversation you want to have at Stage 0, not at Stage 4. + +--- + +## Blast radius — the question Stage 0 exists to answer here + +In every other mode, Stage 0 asks *what do we build first*. Here it asks a second question that has no +equivalent elsewhere: **what does this change touch that nobody mentioned?** + +Work outward from the entities the change affects: + +1. **Associations** — `SHOW ASSOCIATIONS`, then `DESCRIBE ENTITY` each end. An entity you are changing + that is on the far end of an association from a module nobody mentioned is your blast radius. +2. **Microflows that read or write those entities** — `SEARCH` for the entity name across microflows. + A change to a validation rule lands in every flow that writes the entity, not only the one on the + screen you were shown. +3. **Pages bound to them** — `SHOW PAGES IN `, and check which are bound to the entity. +4. **Module dependencies** — `mxcli graph-report`. If the module you are changing is in a tangle, the + blast radius is the tangle. +5. **Published and consumed services** — a changed entity behind a published REST service is a + contract change, and the consumer is not in the `.mpr`. + +**Write the blast radius into `triage.md` as its own section and get it confirmed.** It is the single +most valuable output of Stage 0 in this mode, and it is the thing the person requesting the change is +least able to give you — they know what they want, not what it touches. + +--- + +## What runs, stage by stage + +| Stage | Runs? | What changes in this mode | +|---|---|---| +| **P — Kickoff** | Yes, light | `bin/init-project.sh` as normal. Many intake questions are already answered by the app existing — answer them from the model, not by asking. Record entry mode `Change an existing app` `CONFIRMED` in `PROJECT.md`. | +| **0 — Triage & Scope ✋** | **Yes, always** | Two questions, not one: which slice, and its blast radius (above). The Coverage Matrix's *extraction* rows are N/A — Path D has no extractor to choose. The Business Capability Map is built from `SHOW MODULES` + the change request. **CAC-1 runs.** | +| **1 — Analysis** | Yes, **Path D** | Query the model into the knowledge base, scoped to the slice **plus** its blast radius. Path A is declared not-applicable with attribution, not "skipped". Path C (SME) matters more here than anywhere: the model tells you what the app does and nobody wrote down why. **CAC-1b runs** — its scope-out diff is the slice-vs-app statement. | +| **2 — Requirements** | Yes, **slice only** | One BRD per capability *being changed*, each carrying **as-is** and **to-be**. Do not BRD untouched capabilities; record explicitly that you did not, and why. **CAC-2 and CAC-3 run.** | +| **3 — Architecture & Design ✋** | **Conditionally** | Run it in full if the change crosses module boundaries, adds an integration, or alters the domain model. Otherwise it collapses to: which existing module owns this, and does that still hold. **Never invent new module boundaries for an app that already has them** — `modularize-domain.md` is being used to *check* a boundary here, not to draw one. Wireframes only for screens that change; the design system is the app's existing styling, captured, not designed. **CAC-4 runs, scoped to what changes.** | +| **4 — Build Plan ✋** | Yes, **slice only** | `brd-to-build-plan.md` as normal, over the slice's BRDs. Ordering must respect what already exists: you cannot stub an entity that is live and has data in it. **CAC-5 runs.** | +| **5–6 — Build & Verify** | Yes, unchanged | `iterative-build-loop.md`, the STOP table, module briefs, gates. Plus the rule below. | +| **7 — Cutover** | **N/A** | There is no legacy system to cut over from. Mark it N/A in the register with that reason — an unstated skip and a settled one are different things, which is the whole reason the register exists. | + +--- + +## The rule that is specific to this entry mode + +**Every gate from Stage 5 onward is also a regression gate.** + +In the other modes a gate asks *did we build what we said*. Here it asks that, and one more thing: +*does everything the app did yesterday still work*. That second question is answered by the Track B +baseline from Ground Rule 1, re-run, and by nothing else. + +A module gate that is green on the new work and was never run against the baseline has answered half +the question and reported it as the whole. Re-run the baseline at every module gate, not once at the +end — a regression found three modules later costs the same to fix and much more to find. + +--- + +## Coverage in this mode + +`coverage-ledger.md`'s denominator is **the slice's BRD leaves**, never the app's. This is the one +number most likely to be read as more than it is. + +State it in the ledger header, in these terms: *"N leaves across M BRDs, covering the click-and-collect +change and its blast radius. The remaining 14 modules of this app have no BRD and are not claimed by +this ledger."* A ledger that says `100% covered` without that sentence is telling the reader the app is +fully specified, and it is not. + +`existing-app-assurance.md` documents four fallback levels for a missing ledger and calls **Level 4 · +NOT APPLICABLE** the normal state for an audited app. In this mode the changed modules move up to a +real ledger and the untouched ones stay at Level 4. Both verdicts in one project is correct here, and +it is the only entry mode where that is true. + +--- + +## Deliverables + +- `PROJECT.md` — decision register, entry mode `CONFIRMED`, blast radius confirmed, Stage 7 marked N/A with its reason. +- `triage.md` — slice + blast radius, signed off. +- Knowledge base — Path D, scoped, with counts recorded: modules, and per in-scope module the entity, page and microflow totals `SHOW …` returned, so a reader can see the slice against the app. +- BRDs for the changed slice, each with as-is and to-be — and one line saying how many capabilities were *not* BRD'd and why. +- A build plan over the slice. +- **A regression baseline that was green before the change and is green after it** — stated as N journeys over M modules, re-run at every module gate. Without this the rest is unverified. +- Anything reusable learned about the app → `skills/learned-*.md`; process learnings → `process/process-learnings.md`. diff --git a/skills/learned-mdl-preflight.md b/skills/learned-mdl-preflight.md index 7692418..0e5a3f2 100644 --- a/skills/learned-mdl-preflight.md +++ b/skills/learned-mdl-preflight.md @@ -70,6 +70,7 @@ Once you've picked a mode per operation, run the STOP table below against every --- | 23 | Name any document or entity that **might already exist** — `create or modify` on an entity, or any `create or replace` on a page, layout or microflow | **STOP → run `mxcli diff -p .mpr