diff --git a/CHANGELOG.md b/CHANGELOG.md index 27fa96ab..1a2899e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m ## Unreleased +- fix(build-plan-status): --refresh keeps an existing build-plan.json current, so a day of building no longer reads as 0 built — MendixMau - learn(unit-test): the unit-test skill names the per-flow `Unit flows:` list next to `Unit modules:`, so whether a flow gets a test reads the same in both places (follow-up to #435) — MendixMau - learn(load-test): **new on-demand skill for load testing a page without correlating Mendix's client protocol by hand: Playwright records the real `/xas/` calls, a probe maps each opaque `runtimeOperation` to its microflow through Jaeger, and the chosen call is replayed with the session's own cookie and CSRF token.** Ten field traps (HTTP 200 on a failed action, caught REST errors under a green microflow span, the wrong call hammered, a recording that still held the previous page, a tracing check that failed open, a harness that throttled itself, harness vs app limits, requests vs users, sampled trace counts, empty data) and a four-line report that says what the run does not prove. Routed ondemand for lead, test and review; no instrument ships yet and the roadmap's "no load testing" line is reworded. Field evidence: a warehouse demo app, Mendix 11, 16 runs 2026-09-09 to 2026-10-08, bursts of 1000 and 2000 concurrent calls on one session — MendixMau - new(process-map): **Process map: one swimlane map per business process, each step on its wireframe once screens exist, every open question and ASSUMED decision pinned to the step it is about; drawn twice, a draft at Stage 2 close without screens (pass 1, shown at CAC-3) and the full map at Stage 3 with screens (pass 2, walked at the Stage 3 gate close-out).** `skills/process-map.md` (when, model, anchoring, build, verify by looking) and `project-bin/process-map.js` (`validate`, `anchor`, `build`; Node stdlib, deterministic) with its template. Named "map" because "process" in the progress report means the toolkit's own stages, while this shows the app's business process. With no wireframes, a step may name a screen that is not drawn yet or have none, and a person step stays a person step; once a wireframe exists `validate` fails a step page with no wireframe, a use case on no process and not standalone, a decision with one outcome, two steps in one cell. `anchor` places items mechanically (named microflow, listed or named use case, named screen, overlapping source lines) and keeps judged placements by fingerprint, so a reworded question is unplaced again instead of silently wrong; global buckets are allowed and counted. Wired into the Stage 3 Agent produces and Surface rows, a `process-map` opt-in manifest row (an existing model counts as opting in), the `swimlanes` opt-in row (the model discharges it), CAC-3 and CAC-4, and a check_stage_3 FAIL when the map is older than its model, its anchors or a wireframe. `tests/wave2/test-process-map.sh` on a synthetic order approval fixture with its own committed BRD, covering both passes. Field evidence: a requirements-driven rebuild POC, 2026-10-16, where the reviewer could not tell where the sixty questions fit; the map placed 102 items with 0 unplaced. — MendixMau diff --git a/README.md b/README.md index 59d5cbae..32d73a18 100644 --- a/README.md +++ b/README.md @@ -605,7 +605,7 @@ Every mxcli project has a `.ai-context/skills/` directory (bundled by `mxcli ini |---|---| | Dispatching a build step to a helper — generate its one-file pack (the brief's Build steps row, mxcli brain brief, live DESCRIBEs, example, folder) and hand over the path instead of a reading list. Measured: 25-38% fewer tool calls and 30-41% less time, same quality; the token saving is not proven | `project-bin/context-pack.sh` | | An exec.sh guard refused a write (not a permission prompt), or building a module with mxcli — verified, iterative, coverage-checklist gated; on a refusal: commit, wait or stop, never FORCE_EXEC | `skills/iterative-build-loop.md` | -| After marking a module done, or any time "how much is built vs proven" is asked — renders build-plan.html from done- prefixes and verify-module.sh/improvement-register.md, kept as two honestly separate views; --json writes architecture/build-plan.json parsed from build-plan.md's Phase headings (a plan with no Phase headings gets no file) | `project-bin/build-plan-status.sh` | +| After marking a module done, or any time "how much is built vs proven" is asked — renders build-plan.html from done- prefixes and verify-module.sh/improvement-register.md, kept as two honestly separate views; --json writes architecture/build-plan.json parsed from build-plan.md's Phase headings (a plan with no Phase headings gets no file); --refresh keeps an existing build-plan.json current but never creates one | `project-bin/build-plan-status.sh` | | Turning a client-derived Mendix app into a clean, shareable demo with zero client fingerprint — branding, data, custom widgets | `skills/anonymize-client-app-for-demo.md` | | Handing a headless-built model to a person — opening it in Studio Pro, a free sandbox, or a colleague's machine: the model travels, the demo data and runtime config (keys, an agent's bound model) do not, and each needs its own re-establish step | `skills/handoff-to-studio-pro.md` | | Stage 5 start, before the first module of any entry mode — one entity, flow, page, nav, demo user, journey and screenshot proven in the running app, so build/run/look/test are known to work before a module depends on them | `skills/walking-skeleton.md` | diff --git a/ROUTING.md b/ROUTING.md index e2fe31e1..e75816da 100644 --- a/ROUTING.md +++ b/ROUTING.md @@ -144,7 +144,7 @@ picks the row up. That is the whole procedure — there is no second list to rem | Before any mxcli exec / exec.sh / --mcp write — ask or run? the knob decides | `bin/exec-approval.sh` | mdl,gate | 5,6 | baseline | | Dispatching a build step to a helper — generate its one-file pack (the brief's Build steps row, mxcli brain brief, live DESCRIBEs, example, folder) and hand over the path instead of a reading list. Measured: 25-38% fewer tool calls and 30-41% less time, same quality; the token saving is not proven | `project-bin/context-pack.sh` | mdl | 5 | ondemand | | An exec.sh guard refused a write (not a permission prompt), or building a module with mxcli — verified, iterative, coverage-checklist gated; on a refusal: commit, wait or stop, never FORCE_EXEC | `skills/iterative-build-loop.md` | mdl,gate | 5 | ondemand | -| After marking a module done, or any time "how much is built vs proven" is asked — renders build-plan.html from done- prefixes and verify-module.sh/improvement-register.md, kept as two honestly separate views; --json writes architecture/build-plan.json parsed from build-plan.md's Phase headings (a plan with no Phase headings gets no file) | `project-bin/build-plan-status.sh` | architect,gate,review | 4,5,6 | ondemand | +| After marking a module done, or any time "how much is built vs proven" is asked — renders build-plan.html from done- prefixes and verify-module.sh/improvement-register.md, kept as two honestly separate views; --json writes architecture/build-plan.json parsed from build-plan.md's Phase headings (a plan with no Phase headings gets no file); --refresh keeps an existing build-plan.json current but never creates one | `project-bin/build-plan-status.sh` | architect,gate,review | 4,5,6 | ondemand | | Turning a client-derived Mendix app into a clean, shareable demo with zero client fingerprint — branding, data, custom widgets | `skills/anonymize-client-app-for-demo.md` | mdl,review | 6 | ondemand | | Handing a headless-built model to a person — opening it in Studio Pro, a free sandbox, or a colleague's machine: the model travels, the demo data and runtime config (keys, an agent's bound model) do not, and each needs its own re-establish step | `skills/handoff-to-studio-pro.md` | test,review | 6,7 | ondemand | | Sharing the project with a colleague on Mendix Team Server while the build loop stays on GitHub — content-transplant snapshots between the two clones (status/push/pull); SUPERSEDED by platform-link.md §3 (adopt without rewriting history, field-proven) — only if that path fails; UNPROVEN against a real Team Server | `project-bin/ts-sync.sh` | mdl,gate | 6,7 | experimental | diff --git a/bin/lib/artifact-manifest.tsv b/bin/lib/artifact-manifest.tsv index 6808cadd..e866a5eb 100644 --- a/bin/lib/artifact-manifest.tsv +++ b/bin/lib/artifact-manifest.tsv @@ -92,7 +92,7 @@ wireframes 3 design/wireframes/*.html skills/design-artifacts.md Step 3, one per module-definition 3 architecture/modules/*/definition.md skills/architecture-blueprint.md Step 1 (:60 — the directory shape, one doc per module) THIS ROW IS ITS FIRST MECHANICAL CONSUMER — as of 2026-08-22 nothing executable read definition.md (improvement-plan P7 residue, the newest instance of the pattern this table exists to stop); prose consumers: skills/architecture-blueprint.md:43, skills/coverage-ledger.md:27 migration,requirements,existing-app-change report build-plan 4 architecture/build-plan.md skills/brd-to-build-plan.md bin/gate-check.sh:955 (check_stage_4), project-bin/build-plan-status.sh (progress board), project-bin/coverage-preflight.sh:238 (the claims join) migration,requirements,existing-app-change gate build-plan-html 4 architecture/build-plan.html project-bin/build-plan-status.sh --html (skills/brd-to-build-plan.md:47 — derived view, never hand-edited; refreshed by exec.sh and full gate-check.sh runs via --refresh) conversion-runbook.md §2 Stage-4 Surface row, parsed at bin/gate-check.sh:1284 migration,requirements,existing-app-change report -build-plan-json 4 architecture/build-plan.json project-bin/build-plan-status.sh --json (derived from build-plan.md's Step-5 Phase headings, row tables and claims: blocks, never hand-edited; not written when the markdown has no Phase headings) MXTK Studio Plan room (a view built from data, not from the HTML); nothing in the toolkit reads it and no verdict may depend on it migration,requirements,existing-app-change report +build-plan-json 4 architecture/build-plan.json project-bin/build-plan-status.sh --json (derived from build-plan.md's Step-5 Phase headings, row tables and claims: blocks, never hand-edited; not written when the markdown has no Phase headings; --refresh keeps an existing file current but never creates it) MXTK Studio Plan room (a view built from data, not from the HTML); nothing in the toolkit reads it and no verdict may depend on it migration,requirements,existing-app-change report module-brief 4 architecture/modules/*/module-brief.md|architecture/modules/*-brief.md skills/module-brief.md — ba-agent writes the first at Stage 4, the rest just-in-time bin/gate-check.sh:1121 (build-ready fails without one), project-bin/build-plan-status.sh:109 migration,requirements,existing-app-change gate coverage-ledger 4 architecture/modules/*/coverage-ledger.md|architecture/modules/*-coverage-ledger.md|architecture/coverage-ledger.md skills/coverage-ledger.md procedure at Stage 4 (BRD leaves × build-plan claims); the three shapes are §"Where the ledger lives", first canonical project-bin/conformance-check.sh:85-93, project-bin/coverage-preflight.sh:134-137, project-bin/verify-module.sh:299-300, project-bin/review-module.sh:289, conversion-runbook.md:487 (Stage-4 produces row) — the eleven-consumers-no-producer artifact of improvement-plan Finding 12 migration,requirements report ui-reviews 5 design/ui-reviews/ui-review-*.html skills/module-review.md pass (review-agent), one report per module close-out bin/gate-check.sh:984 (check_stage_6), bin/lib/obligations.tsv:47 (the look row — per-module coverage and denominators live THERE; this row only asks whether the stage produced any report at all) migration,requirements,greenfield,existing-app-change gate diff --git a/bin/lib/skill-routing.tsv b/bin/lib/skill-routing.tsv index 27d8707a..ab3e2207 100644 --- a/bin/lib/skill-routing.tsv +++ b/bin/lib/skill-routing.tsv @@ -188,7 +188,7 @@ tool-output-is-not-ground-truth skills/tool-output-is-not-ground-truth.md Any ti agent-permission-friction skills/agent-permission-friction.md Any refused, denied or blocked command — BEFORE rewriting a permission rule and before telling the user a tool is blocked. A rule matches the START of the command line, so an allowlisted tool prefixed with cd matches nothing all - ondemand diagnose process-coherence-pass skills/process-coherence-pass.md Checking whether the whole journey hangs together rather than each piece — finds correctly-built components nothing reaches, which per-element conformance and UI tests both miss review 5,6 ondemand verify coherence-cadence project-bin/coherence-cadence.sh After every module's CONFIRM stage — counts proven modules since the last cluster/full coherence pass and exits DUE once the threshold is reached, so the cadence isn't left to memory mdl,gate,review 5,6 ondemand verify -build-plan-status project-bin/build-plan-status.sh After marking a module done, or any time "how much is built vs proven" is asked — renders build-plan.html from done- prefixes and verify-module.sh/improvement-register.md, kept as two honestly separate views; --json writes architecture/build-plan.json parsed from build-plan.md's Phase headings (a plan with no Phase headings gets no file) architect,gate,review 4,5,6 ondemand build +build-plan-status project-bin/build-plan-status.sh After marking a module done, or any time "how much is built vs proven" is asked — renders build-plan.html from done- prefixes and verify-module.sh/improvement-register.md, kept as two honestly separate views; --json writes architecture/build-plan.json parsed from build-plan.md's Phase headings (a plan with no Phase headings gets no file); --refresh keeps an existing build-plan.json current but never creates one architect,gate,review 4,5,6 ondemand build e2e-evidence-report skills/e2e-evidence-report.md Turning an already-rigorous run into a narrated proof a stakeholder can trust without running anything test,review 6 ondemand verify record-demo-video skills/record-demo-video.md Recording a narrated screen-capture demo of a running app for a human to watch — opening on the app instead of a blank frame, and keeping captions synced to the pixels test 6 ondemand verify demo-recording-polish skills/demo-recording-polish.md A demo film someone will watch looks captured, not produced — 25 fps smear, scroll jumps, no visible pointer, a dense page nobody can read: 2x CDP screencast at 60 fps, drawn cursor and click ripple, eased scroll, and a zoom rendered afterwards from the click log (never a CSS transform in the page) test 6 ondemand verify diff --git a/project-bin/build-plan-status.sh b/project-bin/build-plan-status.sh index 779ae491..f96bc1b5 100755 --- a/project-bin/build-plan-status.sh +++ b/project-bin/build-plan-status.sh @@ -34,7 +34,9 @@ # by views A and B # --refresh the unattended form of --html, for exec.sh and gate-check.sh: quiet, writes only # when build-plan.md exists, never over a build-plan.html this script did not -# write, and leaves the file untouched when nothing but the timestamp would change +# write, and leaves the file untouched when nothing but the timestamp would change. +# It also keeps an EXISTING architecture/build-plan.json current (same parser as +# --json, same no-rewrite-for-a-timestamp rule) and never creates one # --json also write architecture/build-plan.json, parsed from architecture/build-plan.md's # Step-5 Phase headings, row tables and claims: blocks (see "C." below) # --quiet suppress the stdout table (useful when only --html/--json output is wanted) @@ -425,6 +427,20 @@ if [ "$WRITE_JSON" -eq 1 ] || [ "$WRITE_HTML" -eq 1 ]; then case $? in 0) PLAN_JSON="$PLAN_TARGET" JSON_MSG="wrote ${JSON_OUT#$ROOT/}" + if [ "$REFRESH" -eq 1 ] && [ "$WRITE_JSON" -eq 0 ] && [ -f "$JSON_OUT" ]; then + # --refresh keeps an EXISTING build-plan.json current (never creates one): exec.sh and + # gate-check.sh run --refresh after every build step, so a json written once at Stage 4 + # would otherwise read 0 built after a day of building. Same parser as --json; the + # write is skipped when only generatedAt would differ, like the html below. + if "$PY" -c 'import json,sys +def load(f): + d=json.load(open(f,encoding="utf-8")); d.pop("generatedAt",None); return d +sys.exit(0 if load(sys.argv[1])==load(sys.argv[2]) else 1)' "$JSON_OUT" "$PLAN_TARGET" >/dev/null 2>&1; then + JSON_MSG="${JSON_OUT#$ROOT/} already current" + else + cp -f "$PLAN_TARGET" "$JSON_OUT" 2>/dev/null && JSON_MSG="refreshed ${JSON_OUT#$ROOT/}" + fi + fi if [ "$WRITE_JSON" -eq 1 ]; then # A producer guarantees its own output is ignored (snapshot-mpr.sh's rule). The JSON # is a build product: regenerated on demand in under a second, derived entirely from diff --git a/tests/wave2/test-build-plan-json.sh b/tests/wave2/test-build-plan-json.sh index 589813d7..07410fdf 100644 --- a/tests/wave2/test-build-plan-json.sh +++ b/tests/wave2/test-build-plan-json.sh @@ -39,6 +39,8 @@ # --json, a `done-` script reads done-, and a row whose State says built while its script # is not done- is flagged. --refresh leaves an unchanged page byte-identical, never writes # over a page this script did not generate, and writes nothing without a build-plan.md. +# T11 --refresh keeps an existing build-plan.json current (a State flipped in the md shows in +# the json), rewrites nothing when only generatedAt would differ, and never creates a json. # # Usage: bash tests/wave2/test-build-plan-json.sh /path/to/build-plan-status.sh @@ -365,6 +367,33 @@ P10B="$(new_project htmlnoplan)" bash "$SCRIPT" "$P10B" --refresh >/dev/null 2>&1 [ ! -f "$P10B/architecture/build-plan.html" ] && ok "T10 --refresh writes nothing without build-plan.md" || bad "T10 --refresh wrote a page with no plan" +# ── T11: --refresh keeps an existing build-plan.json current, never creates one ── +P11="$(new_project jsonrefresh)" +cat > "$P11/architecture/build-plan.md" <<'MD' +# Build Plan + +### Phase 1 — Alpha + +| # | Kind | Step | Produces/Proves | Depends on | Skills | State | +|---|---|---|---|---|---|---| +| 1.1 | script | `01-alpha.mdl` | Alpha entity | — | — | not built | +MD +J11="$P11/architecture/build-plan.json" +bash "$SCRIPT" "$P11" --json --quiet >/dev/null 2>&1 +q "$J11" "json.dumps(d)" | grep -q 'not built' && ok "T11 --json snapshot shows the row not built" || bad "T11 setup: snapshot not 'not built'" "$(cat "$J11" 2>/dev/null)" +sed 's/| not built |/| built |/' "$P11/architecture/build-plan.md" > "$P11/md.tmp" && mv "$P11/md.tmp" "$P11/architecture/build-plan.md" +bash "$SCRIPT" "$P11" --refresh >/dev/null 2>&1 +S11="$(q "$J11" "d['phases'][0]['steps'][0]")" +case "$S11" in *"'not built'"*|*PARSE-ERROR*) bad "T11 --refresh left the json stale" "$S11" ;; *built*) ok "T11 --refresh updates the existing json to built" ;; *) bad "T11 unexpected step" "$S11" ;; esac +SUM11="$(cksum < "$J11")" +sleep 1 +bash "$SCRIPT" "$P11" --refresh >/dev/null 2>&1 +[ "$(cksum < "$J11")" = "$SUM11" ] && ok "T11 --refresh rewrites nothing when only the timestamp would change" || bad "T11 --refresh rewrote an unchanged json" +P11B="$(new_project jsonrefreshnone)" +cp "$P11/architecture/build-plan.md" "$P11B/architecture/build-plan.md" +bash "$SCRIPT" "$P11B" --refresh >/dev/null 2>&1 +[ ! -f "$P11B/architecture/build-plan.json" ] && ok "T11 --refresh does not create a json when there is none" || bad "T11 --refresh created build-plan.json" + echo "" echo "PASS=$PASS FAIL=$FAIL ($WORK)" [ "$FAIL" -eq 0 ]