From cb2ab4691a6a5055dba6153dfc9484ddba7e433b Mon Sep 17 00:00:00 2001 From: saingge <262679532+saingge@users.noreply.github.com> Date: Wed, 21 Oct 2026 16:34:44 +0200 Subject: [PATCH] fix(graph-sweep, lint): name pluggable-widget properties as a reference the catalog can miss graph-sweep's orphan caveat named only layout snippet calls, so a live flow read as "strong evidence of deadness". The orphan list now notes that a flow used only as a pluggable widget's datasource or action property may have no edge, and prints the one search that finds the page that holds it (it needs a REFRESH CATALOG FULL SOURCE catalog, which the note says). The same wording is fixed in review-report.js, and the QUAL004 row in lint-that-actually-runs.md goes from "likely misses" to what was observed, with the issue link. Observed on a Mendix 10.24 app with mxcli v0.27.0 (catalog from REFRESH CATALOG FULL): 5 flows used only as a Gallery's or a third-party widget's microflow datasource had 0 refs rows, "show references to" said "no references found", "describe page" printed each, and QUAL004 flagged each. A Gallery with a microflow datasource and no microflow onClick had its ref (15 of 15); with both, only the onClick ref (2 of 2). The two Data grid 2 microflow datasources in the app had theirs. Test: test-catalog-edge-guard.sh case 1 asserts the note; run against master's graph-sweep.sh at 393d253 it fails on both layouts (22 of 24), with the change it passes 24 of 24. The printed search was run on a copy of the app with a FULL SOURCE catalog and listed the page holding the flow; on a plain FULL catalog it finds nothing and mxcli says so. --- CHANGELOG.md | 1 + bug-logs/mxcli-bugs.md | 2 +- .../qual004-dg2-datasource-ref.md | 2 +- project-bin/graph-sweep.sh | 12 ++++++++++-- project-tests/e2e/review-report.js | 6 ++++-- skills/lint-that-actually-runs.md | 2 +- tests/wave2/test-catalog-edge-guard.sh | 10 ++++++++++ 7 files changed, 28 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee82ab78..9db0458d 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(graph-sweep, lint): **the orphan list now says a flow used only by a pluggable widget's datasource or action property may have no catalog edge, and prints the one `mxcli search` that finds the page (it needs a `REFRESH CATALOG FULL SOURCE` catalog; this sweep reads a FULL one, so the note says to rebuild).** The caveat named only layout snippet calls, so a live flow read as "strong evidence of deadness" (`graph-sweep.sh` comment, `review-report.js` orphan detail, and the `lint-that-actually-runs.md` QUAL004 row, which only said the catalog "likely misses" the ref). Observed on a Mendix 10.24 app with mxcli v0.27.0: 5 live flows used only as a Gallery's or a third-party widget's microflow datasource had 0 `refs` rows, `show references to` said "no references found", `describe page` printed each, and QUAL004 flagged each. A Gallery with a microflow datasource and no microflow `onClick` had its ref (15 of 15); with both, only the `onClick` ref (2 of 2); the two Data grid 2 microflow datasources had theirs. The QUAL004 row now states that and links [mendixlabs/mxcli#1513](https://github.com/mendixlabs/mxcli/issues/1513) (open; reported for Data grid 2 on v0.26.0); the ledger entry and the pending-issue draft now say they are filed. Pinned by `test-catalog-edge-guard.sh` case 1 (fails on 393d253). — saingge - fix(progress-report, build-plan-status): **HARNESS rows are no longer counted as built rows, and a module's `verify-module.sh` row shows once, as that module's sign-off status on its phase card, instead of as a row.** A HARNESS step is a module's sign-off, not a build, so it is out of every "x of y built" count: the phase cards, the plan rollup and the Stage 5 card in `progress-report.html`, and the lede of `build-plan-status.sh --html` ("N build rows", plus a "Not counted: N HARNESS rows" note). The verify row's evidence is read exactly as #501 reads it (`harness_verify`'s rule, now `verify_evidence` + `module_status` in `progress-report.py`; nothing new measured, no extra script run, no mxcli or mxbuild call) and shown as one line per module: `Verified ✓ (LOOK n/n)`, `Verify owed - LOOK + CONFIRM`, `Verify stale (N builds since)` (or `(a script was marked done- after it)`), `Verify not run`, `built? no verify summary`, `Verify not clean ()` for a summary with a FAULT, FINDING or SKIPPED row, or `Verify clean , LOOK n/n - held: State says ` when State is blocked or pending a person (held is not signed off, as #501 never promoted it); a State cell that disagrees is flagged under it, the rollup says how many modules are verified, and the Stage 5 card, KPI and owed text add ", k of n modules signed off". The Phase state badge is read from the build rows only (a phase of HARNESS rows alone says "sign-off only" and its card "Sign-off phase: no build rows"). A module with no verify row shows no status. Other HARNESS rows (a coherence pass, a harness run) stay in the row list, marked "(not counted)". `build-plan.md`, `build-plan.json` and the text output are unchanged, so agents still see every HARNESS step. **Behaviour change to check in your project:** the progress report's built counts drop the HARNESS rows (a plan of 10 rows with 2 HARNESS reads "x of 8"), and the verify rows leave the row tables. Fixture: `test-progress-harness-verify.sh` (H1-H10, N1-N6, both layouts). — MendixMau (decision 2026-10-21) - fix(exec): **a script restated from a stale DESCRIBE now WARNs instead of silently reverting an earlier exec** (#261). A script drafted from a DESCRIBE taken before an earlier script of the batch ran put four old messages back, with check, mxbuild and lint green. New `project-bin/describe-baseline.sh stamp` writes `-- baseline: sha256=` (plus `-- baseline-mxcli: `) from a DESCRIBE at draft time; `exec.sh` runs `verify` only for a script that carries the header, so other scripts cost one grep and no mxcli call. It reports DRIFT with the first lines of the diff, STALEHEADER, and RESTAMP after an mxcli upgrade (DESCRIBE text may change, so that is not called drift). A re-run by the script's own last recorded write (the #269 ledger) and a fresh model are not drift. Nothing is refused and the exit codes do not change. Preflight STOP 21 gains one clause (`-- supersedes:`, `stamp`, exec.sh only warns) and its trigger names `create or modify` (+24 words). Not-found DESCRIBE and `--version` output are captured from mxcli v0.26.0. Lands after the #269 PR; with it, supersedes draft #311. **Behaviour change to check in your project:** `exec.sh` output can carry `WARN: stale draft: …` lines, and the BUILD-LOG detail cell `WARN stale baseline: `; `MXTK_RESTATE_GUARD=off` skips the check. — AlvinnYeo (#261) - fix(exec): **re-running an older `mdlsource/` script over a newer owner's live work now WARNs instead of passing silently** (#269). Three field apps had 99/579, 130/357 and 38/159 documents created by more than one script, and a replay of an older one reverted the newer with exit 0 and every gate green. New `project-bin/script-owners.sh` maps each microflow, nanoflow, page and snippet to the scripts that create or restate it, in run order (digit runs compared as numbers, so `2-core/` runs before `11-fixes/`; `done-` ignored), and reads `-- supersedes:` / `-- superseded-by:` headers. `exec.sh` records every kept write in a machine-local last-writer ledger (`.claude/loop/script-owners/`, self-gitignored, compacted per write); `restore-mpr.sh` marks it on a manual restore. A replay WARNs only when the newer owner's write is live: ledger first, else one DESCRIBE per document, at most 5 per exec (the rest print `CONFLICT (not checked)`). A new owner without a supersedes header gets one `NOTE:` line on its first run, kept out of BUILD-LOG. Nothing is refused and the exit codes do not change. With no co-owner, `exec.sh` runs one grep over `mdlsource/` and no mxcli call. `gate-check.sh` prints the co-owned count when it is above 0. Part of the rebuilt draft #311 (with the #261 PR). **Behaviour change to check in your project:** `exec.sh` output can carry `WARN: restatement: …` and `NOTE: new owner of …` lines; the BUILD-LOG detail cell can carry `WARN reverts: `. Set `MXTK_RESTATE_GUARD=off` to skip the check. — MendixMau (#269) diff --git a/bug-logs/mxcli-bugs.md b/bug-logs/mxcli-bugs.md index 141be2bd..5edc85bc 100644 --- a/bug-logs/mxcli-bugs.md +++ b/bug-logs/mxcli-bugs.md @@ -7027,7 +7027,7 @@ end; ## BUG-DRAFT-qual004-dg2-datasource: QUAL004 reports a `DS_` microflow as "not called from anywhere" when its only caller is a Data grid 2 datasource, and the lint ratchet fails a correct script (2026-10-14) -> **NOT YET FILED.** Upstream draft: `bug-logs/pending-github-issues/qual004-dg2-datasource-ref.md`. +> **Filed:** [mendixlabs/mxcli#1513](https://github.com/mendixlabs/mxcli/issues/1513) (2026-10-16, open). Upstream draft: `bug-logs/pending-github-issues/qual004-dg2-datasource-ref.md`. **Discovered:** 2026-10-14, on an existing-app change project (a connector app). A build row created a page whose Data grid 2 is driven by a new `DS__` microflow, in one script; the navigation entry came in a later script. **Reproducible:** seen twice on one model, not yet reduced to a blank app. **mxcli version:** v0.26.0. **Mendix:** 11.15.0. macOS. diff --git a/bug-logs/pending-github-issues/qual004-dg2-datasource-ref.md b/bug-logs/pending-github-issues/qual004-dg2-datasource-ref.md index 0b5d9b22..9a182617 100644 --- a/bug-logs/pending-github-issues/qual004-dg2-datasource-ref.md +++ b/bug-logs/pending-github-issues/qual004-dg2-datasource-ref.md @@ -1,6 +1,6 @@ Repo: mendixlabs/mxcli Source: toolkit issue #360; `bug-logs/mxcli-bugs.md` BUG-DRAFT-qual004-dg2-datasource -Status: **NOT FILED.** Reduce to a blank app first: one page, one Data grid 2 on a `DS_` microflow, `mxcli lint`, then the same with a classic list view. +Status: **FILED — https://github.com/mendixlabs/mxcli/issues/1513 (2026-10-16)**. Not reduced to a blank app, and not retested on v0.27.0 when filed. --- everything above this line is stripped before filing --- diff --git a/project-bin/graph-sweep.sh b/project-bin/graph-sweep.sh index 35e4647e..5ecd124e 100755 --- a/project-bin/graph-sweep.sh +++ b/project-bin/graph-sweep.sh @@ -183,8 +183,12 @@ ORDER BY COALESCE(i.n,0) ASC, e.n DESC; # --- finding 2: orphaned microflows ----------------------------------------------------------- # No inbound call / page action / nav item. Entry-point prefixes are excluded: they are -# legitimately unreferenced. Note SHOW REFERENCES TO misses layout snippetcalls, so this is -# strong evidence of deadness, not proof. +# legitimately unreferenced. The catalog also records no edge for some pluggable-widget +# properties (observed on mxcli v0.27.0: a Gallery's microflow `DataSource` when the Gallery also +# has a microflow `onClick`, and a third-party widget's datasource and action properties), and +# SHOW REFERENCES TO misses layout snippetcalls. So this is evidence of deadness, not proof: +# check the page source before deleting a flow (the report prints the command; see also +# skills/lint-that-actually-runs.md). ORPHANS="$(q " SELECT m.QualifiedName, m.ActivityCount FROM microflows_data m @@ -228,6 +232,10 @@ echo " orphaned microflows (no call / action / nav inbound, entry-point prefixe if [ "$N_ORPH" -gt 0 ]; then printf '%s\n' "$ORPHANS" | awk -F'|' 'NF {printf " %-56s %s activities\n", $1, $2}' | head -40 [ "$N_ORPH" -gt 40 ] && echo " ... and $((N_ORPH-40)) more" + echo " NOTE: a flow used only as a pluggable widget's datasource or action property may have no edge, so it can" + echo " be listed here. Before deleting one, find the page that holds it: rebuild with 'REFRESH CATALOG FULL SOURCE'" + echo " (a plain FULL catalog has no page source), then look for a PAGE row under 'Source Matches':" + echo " ./mxcli -p \"$MPR\" search \"\"" fi echo diff --git a/project-tests/e2e/review-report.js b/project-tests/e2e/review-report.js index 7cf79982..9e295d8f 100644 --- a/project-tests/e2e/review-report.js +++ b/project-tests/e2e/review-report.js @@ -344,8 +344,10 @@ if (graphParsed) { verdict: 'manual', provenance: 'judged', detail: (f[2] || '?') + ' activities, and no inbound call / action / menu_item / ' + 'show_page / datasource edge. Entry-point prefixes are already excluded. ' + - 'SHOW REFERENCES TO misses layout snippetcalls, so this is strong evidence of ' + - 'deadness, not proof.', + 'The catalog records no edge for some pluggable-widget properties (a datasource or ' + + 'action set there) and SHOW REFERENCES TO misses layout snippetcalls, so this is ' + + 'evidence of deadness, not proof: find the page that holds the flow (a source-catalog search) ' + + 'before deleting it.', measuredAt: STARTED, nonVacuity: { controlRan: false, note: 'graph sweep has no positive control' }, evidence: [{ type: 'query', sql: 'microflows_data LEFT JOIN refs (catalog.db)', diff --git a/skills/lint-that-actually-runs.md b/skills/lint-that-actually-runs.md index dd3329c0..de86a8db 100644 --- a/skills/lint-that-actually-runs.md +++ b/skills/lint-that-actually-runs.md @@ -168,7 +168,7 @@ onto the wrong document. Each answer is the user's decision, recorded in `PROJEC | Finding | Why it is not a defect | What to do today | |---|---|---| -| **QUAL004** on a `DS_` flow whose only caller is a Data grid 2 datasource (#360) | The stock rule already counts `datasource` refs (v0.24.0+), yet v0.26.0 flagged two working Data grid 2 datasources. The catalog likely misses the pluggable widget's ref. | Confirm with `describe page`, then accept the rise: `--update-baseline --reason "QUAL004 DS_ datasource false positive"`. Never rename or add a caller. Upstream: `pending-github-issues/qual004-dg2-datasource-ref.md` | +| **QUAL004** on a `DS_` flow whose only reference is a pluggable widget's datasource (#360) | The stock rule counts `datasource` refs (v0.24.0+), but the catalog drops some pluggable-widget refs: v0.26.0 flagged two working Data grid 2 datasources. On v0.27.0 (Mendix 10.24, one app) a Gallery with a microflow `DataSource` and a microflow `onClick` keeps only the `onClick` ref (2 of 2); one without `onClick` keeps its ref (15 of 15); a third-party widget's datasources have none (3 of 3). `show references to` then says "no references found", while `describe page` shows the flow. | Find the page with `mxcli search ""` on a `REFRESH CATALOG FULL SOURCE` catalog (a PAGE row under "Source Matches"). Then accept the rise: `--update-baseline --reason "QUAL004 DS_ datasource false positive"`. Never rename or add a caller. Upstream: [mendixlabs/mxcli#1513](https://github.com/mendixlabs/mxcli/issues/1513) (open; Data grid 2, v0.26.0); draft `bug-logs/pending-github-issues/qual004-dg2-datasource-ref.md` | | **QUAL004** on a `TEST_` helper (#241) | It is called from `tests/*.test.mdl`, which lint cannot see. `ENTRY_POINT_PREFIXES` is a constant, not an option. | Baseline with a reason. Keep QUAL004 on: it is the orphan check `process-coherence-pass.md` runs. Upstream: `pending-github-issues/lint-naming-prefixes-as-options.md` | | **CUSTOM002** on `TEST_`, `GET_`, `PRS_`, `STUB_` (#241) | `example_microflow.star` is an *example* rule from `mxcli init` ("customize the prefixes"). Its `VALID_PREFIXES` is a constant. | `rules: CUSTOM002: enabled: false`, recorded in `PROJECT.md`, or baseline with a reason. Never edit the `.star` file. Upstream: `pending-github-issues/lint-naming-prefixes-as-options.md` | | **QUAL002** on import mappings, published REST services and Marketplace Java actions (#246) | MDL cannot store documentation on the first two (MDL089); a doc comment above them moves to the next microflow. | The rule has per-kind options (mxcli >= 0.24.0): `rules: QUAL002: options: check_import_mappings: false`, `check_published_rest_services: false`, `check_java_actions: false`, `check_java_action_params: false`. Or document them in Studio Pro. Upstream: `pending-github-issues/qual002-skip-mdl089-types.md` | diff --git a/tests/wave2/test-catalog-edge-guard.sh b/tests/wave2/test-catalog-edge-guard.sh index 2206710a..95d3d554 100755 --- a/tests/wave2/test-catalog-edge-guard.sh +++ b/tests/wave2/test-catalog-edge-guard.sh @@ -23,6 +23,7 @@ # 4. build_mode 'fast' + empty refs -> FAULT, as before # 4b. refs typed, but none of the orphan-read kinds -> sweeps, with the orphan-list WARNING # 5. app-facts: 'source' + calls and action-only both pass the guard; kind-less FAULTs +# (case 1 also asserts the orphan list's note on pluggable-widget datasource/action properties) # # The catalog databases are SYNTHETIC: no real catalog.db is captured in this repo, and the # report quotes only the FAULT line and the counts. Tables and columns are exactly the ones the @@ -120,6 +121,15 @@ for layout in single two; do else bad "[$layout] orphan finding wrong on a 'source' catalog" "$(out)" fi + # The orphan list must say that a flow used only by a pluggable widget's datasource/action + # property has no edge, and print the one search that finds the page holding it (it needs + # a SOURCE catalog, which this sweep's FULL catalog is not). + if grep -q "NOTE: a flow used only as a pluggable widget's datasource or action property may have no edge" "$WORK/out" \ + && grep -q "REFRESH CATALOG FULL SOURCE" "$WORK/out" && grep -q 'search ".*"' "$WORK/out"; then + ok "[$layout] orphan list carries the pluggable-widget note and the source-search command" + else + bad "[$layout] orphan list lacks the pluggable-widget note" "$(out)" + fi # --- 2. no microflow-to-microflow calls at all: still sweeps (the review-caught regression) ---- P="$(proj $layout)"; mkdb "$(mdir "$P")/.mxcli/catalog.db" full actions