Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m

## Unreleased

- learn(lint): **known answers for four stock-rule findings on the toolkit's own conventions, and four modelling-error rule candidates.** New table in `lint-that-actually-runs.md`, with one entry for each finding. QUAL004 on a `DS_` flow used only as a Data grid 2 datasource (seen on v0.26.0 although the rule counts `datasource` refs) is accepted into the baseline with a reason, never renamed or given a fake caller (#360, BUG-DRAFT-qual004-dg2-datasource). QUAL004 on `TEST_` helpers and CUSTOM002 on `TEST_`/`GET_`/`PRS_`/`STUB_` are handled by baselining them with a reason, or (CUSTOM002) by `enabled: false` recorded in `PROJECT.md` (#241). QUAL002 on import mappings and published REST services, which MDL cannot document (MDL089), is handled by the rule's existing per-kind options (`check_import_mappings`, `check_published_rest_services`; #246). `process-coherence-pass.md` warns against deleting either QUAL004 kind. Upstream drafts for all three are in `bug-logs/pending-github-issues/`. `process/lint-backlog.md` Batch 7 adds the four missing #169 candidates (rows 51–54), and its inbox file is promoted and deleted. — joshuamoesa (#360), MendixMau (#241, #246, #169)
- process(build): **Stage 5 drafts the ready set in parallel and applies serially.** The runbook dispatch row said "sequential within a module", which serialised drafting even for independent scripts; it now points to `iterative-build-loop.md` → Gate cost, the single statement of the rule. The unit is the build-plan row: every `BUILD` row whose "Depends on" rows are all applied, minus overlapping writers (two rows that replace, alter or drop+create the same document never share a ready set, and no row is drafted while it overlaps a queued unapplied one; `brd-to-build-plan.md` has Produces name every document a row writes), runs at once, its scripts in order, one `mdl-agent` per script. Applies stay one at a time through `bin/exec.sh`, and the ready set is recomputed after each. A queued draft made before a sibling apply landed is re-checked with `mxcli diff --format struct` (preflight STOP rule 23); any removal line (checked against `describe` per BUG-146) or STOP rule 21 target means re-draft, never patch, because a stale restatement of a shared document is exactly rule 21's silent seed-call loss and passes `check --references`. Report `ready set N, drafted N, applied k`; the `mdl-agent` template says a drafter never applies and never depends on an unapplied draft. Field evidence: none yet. — MendixMau
- fix(platform-link): **CLI commits now show their changed documents in Studio Pro History.** Studio Pro's History → Model changes pane reads a `ModelChanges` array from the commit's `refs/notes/mx_metadata` note. Trap 6c's hand-written template set it to `[]`, so every mxcli/agent commit showed "Model changes 0" (field project: 270 of 270 notes empty). New `project-bin/mx-metadata-note.py` (stdlib only) computes the array from the commit's changed `.mxunit` files, in Studio Pro's entry shape: Status, UnitID, UnitType, UnitName and Module (walked up the `.mpr` Unit tree). It has `changes` / `write` / `backfill` / `sync <remote>` subcommands. `install-project-hooks.sh` now also installs post-commit and post-rewrite hooks that write the note and never block, and `--check` covers them, so `sync-project.sh` rolls them out to wired projects. Notes are published with `mx-metadata-note.py sync <remote>` after the branch push. Push config is never touched. With mxcli v0.26+ in the project root the hooks call `mxcli git note --write` instead (mendixlabs/mxcli#1337); the Python script is the fallback for older pins, and on 160 field commits both wrote the same 3,594 entries. Trap 6c rewritten. Measured against Studio Pro's own notes, 51 commits in 5 apps: 3387/3389 entries exact on all five fields. Field run on a 357-commit Mendix 11.15.0 app: 158 notes backfilled and pushed, and Studio Pro History lists the documents per revision. Review fixes: an earlier revision added `HEAD` + the notes ref to `remote.<r>.push`. It was dropped because any push refspec replaces `push.default`. A branch tracking a differently named upstream got a new same-named branch on Team Server where `simple` refuses, a missing local notes ref failed the whole push, and nobody knows whether Studio Pro's own push reads that config. The installer now only fetches the remote's notes (non-forced). It removes that exact `HEAD` + notes pair if present, and leaves and reports any other entry. `sync` handles a remote with no notes ref (it used to exit 1) and retries a rejected push once after re-merging. A note that already lists changes (Studio Pro's) is never overwritten by `write`/`backfill` without `--force`, and `sync` keeps a colleague's non-empty note over ours. The mxcli probe greps `git note --help` for `--write`. Hooks and docs call the script through `resolve_py`. Fixture `tests/wave2/test-mx-metadata-note.sh` (40 cases, over real captured template units; single- and two-tree layouts, amend, backfill and `--force`, push exit codes identical to a no-hooks clone, leftover-refspec cleanup, sync to an empty remote and its retry, notes fetch at install, a diverged notes merge; green under `init.defaultBranch` master and main). — field project (Mendix 11.15 app), MendixMau
- learn(fixture-seeding): **explore the data structure first, choose rows by use case, scan actions for resets before any run.** Two seeding runs on public template apps: seeding raised journey passes 33 -> 58 and 20 -> 51 of the same sets (FAIL 93 -> 68, 163 -> 132; INVALID unchanged), and a "Reset all demodata" journey wiped accounts so 104 of 127 journeys reported `The username or password you entered is incorrect`, identical on empty and seeded databases. Skill gains three questions a seed must answer, a use-case checklist, a destructive-action scan, a generic traps table with symptoms, measured expectations and a denominator checklist; routing trigger now fires on seed/test/demo data and empty pages. Independent review fixes: object ids follow the Mendix bigint pattern with a business-key guard (no uuids), associations are seeded where the page's path stores them, four new traps (enum names, inheritance chain, calculated attributes, view/external entities), and the port-offset and container-label traps moved to `harness-architecture.md`. — MendixMau
Expand Down
27 changes: 26 additions & 1 deletion bug-logs/mxcli-bugs.md
Original file line number Diff line number Diff line change
Expand Up @@ -5949,7 +5949,9 @@ service and its callers.
4. **Doc comments** (`/** */`) set documentation on microflows, entities and Java actions. Before an
import or export mapping, or a published REST service, they are silently ignored
("already in sync"). Before a Java action parameter they are a syntax error. QUAL002 therefore
cannot be cleared for those from MDL. Add a baseline entry with the reason.
cannot be cleared for those from MDL. Add a baseline entry with the reason, or switch that kind
off in QUAL002's options (`check_import_mappings`, `check_published_rest_services`; mxcli
>= 0.24.0). The MDL089 warning on v0.25.0 names the case (#246).
5. **`import from mapping … ($Call/ResponseBody)` is a parse error** ("mismatched input '/'"). The
source must be a variable: `declare $Body String = $Call/ResponseBody;` then `($Body)`.
6. **Import mappings, re-run.**
Expand Down Expand Up @@ -6950,3 +6952,26 @@ Two related findings from reading the v0.26.0 source (not field-run):
matching the project. Recipe and the rule-set comparison to run before any diff:
`skills/lint-that-actually-runs.md` → "Linting a copy of the model". `lint-gate.sh`'s collapse
guard catches this inside the gate. Nothing catches it when lint is run directly.

## 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`.

**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_<Entity>_<Verb>` 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.

**What happens.** `check` and mxbuild were clean. `exec.sh`'s lint ratchet then reported:

```
[QUAL004] at <Module>.<Module>.DS_<Entity>_GetConfiguration
✗ lint: rule(s) rose vs baseline — QUAL004 (+1)
✗ Script applied and mxbuild is clean, but LINT ROSE — this is not a pass.
```

Both flagged flows are Data grid 2 datasources on pages in the same module and work in the running app. The datasource is the only reference they will ever have, so the finding never clears.

**What is odd.** The v0.26.0 `orphaned_elements.star` that `mxcli init` writes already counts `datasource` as an inbound kind (`MICROFLOW_ENTRY_KINDS`), and its header names a `DS_` page-datasource false positive as fixed. So the gap is most likely in what the catalog records for a **pluggable** widget's datasource (Data grid 2), not in the rule. Not probed: whether a classic data view or list view datasource clears the same finding on the same model.

**Toolkit side:** do not rename the flow or add a fake caller. Accept the rise with `bin/lint-gate.sh --update-baseline --reason "QUAL004 DS_ datasource false positive (BUG-DRAFT-qual004-dg2-datasource)"`. `skills/lint-that-actually-runs.md` → "Stock rules against the toolkit's own conventions".

**Expected:** a `DataSource: microflow X` on any widget, pluggable or not, is an inbound reference to X. `describe page` already prints it.
22 changes: 22 additions & 0 deletions bug-logs/pending-github-issues/lint-naming-prefixes-as-options.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Repo: mendixlabs/mxcli
Source: toolkit issue #241 (173 of 759 findings on one toolkit-built project were CUSTOM002/QUAL004 on the toolkit's own prefixes)
Status: **NOT FILED.**

--- everything above this line is stripped before filing ---

**Title:** Let projects set QUAL004's entry-point prefixes and CUSTOM002's valid prefixes via lint-config.yaml

## Environment

- mxcli **v0.25.0 / v0.26.0** (the `orphaned_elements.star` and `example_microflow.star` that `mxcli init` writes)

`orphaned_elements.star` (QUAL004) hard-codes `ENTRY_POINT_PREFIXES = ["ACT_", "SCH_", "WS_", "REST_", "OData_"]`
and `example_microflow.star` (CUSTOM002) hard-codes `VALID_PREFIXES`. Neither calls `get_option()`, so
a project can only change them by editing the seeded file, which the next `mxcli init` overwrites without
warning. On one project 84 QUAL004 findings (83 of them `TEST_` helpers called only from
`tests/*.test.mdl`) and 121 CUSTOM002 findings (`TEST_` 90, `GET_` 25, `PRS_` 4) were conventions,
not defects.

Asks:
1. Read both lists with `get_option()` (one comma-separated text, since list options arrive as `None`), keeping today's values as defaults.
2. QUAL004: count a microflow named in `tests/**/*.test.mdl` as called, or exempt a configurable test prefix.
28 changes: 28 additions & 0 deletions bug-logs/pending-github-issues/qual002-skip-mdl089-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Repo: mendixlabs/mxcli
Source: toolkit issue #246; `bug-logs/mxcli-bugs.md` (published REST services section, item 4)
Status: **NOT FILED.**

--- everything above this line is stripped before filing ---

**Title:** QUAL002 asks for documentation on document types MDL cannot document (MDL089)

## Environment

- mxcli **v0.25.0** (measured), v0.26.0 rule text unchanged on this point

On one project 45 QUAL002 findings: ImportMapping 29, JavaAction 11, PublishedRestService 2,
Page/ImageCollection/JsonStructure 3. For published REST services and import mappings a `/** */`
comment cannot store documentation:

```
⚠ the doc comment before `create or modify published rest service … "ServiceBulletins"` is lost: that statement cannot store documentation, so the comment is ignored; the next statement that can take it is `create or modify microflow …` [MDL089]
```

Without the warning the comment lands on the next microflow and overwrites its documentation. In an
mxcli-only workflow those findings can only be closed in Studio Pro.

Asks:
1. For the MDL089 set, change the suggestion to "document it in Studio Pro (MDL cannot store documentation here, MDL089)", or report at a lower severity.
2. Better: let MDL store documentation on these types.

Today's workaround: the per-kind options `check_import_mappings` / `check_published_rest_services` set to `false` in `lint-config.yaml`.
21 changes: 21 additions & 0 deletions bug-logs/pending-github-issues/qual004-dg2-datasource-ref.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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.

--- everything above this line is stripped before filing ---

**Title:** QUAL004 flags a microflow used only as a Data grid 2 datasource as "not called from anywhere"

## Environment

- mxcli **v0.26.0**
- Mendix **11.15.0**
- macOS

A microflow whose only reference is the `DataSource: microflow` of a Data grid 2 is reported by
QUAL004 ("is not called from anywhere. Remove if unused"). `describe page` prints the datasource,
and the app works. `orphaned_elements.star` already lists `datasource` in `MICROFLOW_ENTRY_KINDS`,
so the catalog probably records no `datasource` ref for a pluggable widget's datasource.

Ask: record a pluggable widget's microflow/nanoflow datasource as a `datasource` ref, the same as a
classic data view or list view. Following the rule's suggestion deletes a live datasource.
21 changes: 0 additions & 21 deletions contrib/inbox/2026-09-29-lint-rules-recurring-modelling-errors.md

This file was deleted.

30 changes: 30 additions & 0 deletions process/lint-backlog.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,34 @@ says a role is external. Lint Batch 4 shipped both rows; the field-run counts ar
| 49 | External role (configured) can write all members, a state enumeration (`Status`/`State`/`Result`/`Stage`/`Phase`), an audit `…At`/`…By` attribute, or the association its own XPath scopes ownership on (SEC014) | security | #268: a partner role held `create, read *, write *` on two self-owned entities with a state attribute; lint showed only CONV006 +4, re-baselined; a manual review found it five days later | `permissions_for()` `MEMBER_WRITE` rows, `attributes_for().data_type` (`Enumeration`), `user_roles()` / `role_mappings()`; `external_roles` option, text not list; absent = sync NOTE, not a `_rule` finding. Probed 2026-10-13 | drafted (Batch 4) |
| 50 | CONV009 threshold read from `lint-config.yaml` (`maxObjects`, `countLoopBodies`) instead of the stock hard-coded 15 | quality | #267: the generated config's own example does nothing; three apps at 36 / 30 / 5 findings, one app split flows only to satisfy the 15 | `get_option()`; `total_activity_count` (mxcli >= 0.25.0) for loop bodies. Default kept at 15: raising it for every project is a maintainer call | drafted (Batch 4) |

## Batch 7 — modelling errors that hit both arms, and stock-rule false positives

Source: issue #169, from a field comparison on 2026-09-29: an mxcli + toolkit build and a Studio Pro
MCP build of the same frozen spec, about 75 defects between them. Four or five modelling errors
appeared in both builds independently, so they come from the spec or the platform, not the authoring
tool. Hypothesis: these rules would have prevented 6–8 of the 75. The page-button refresh candidate
is row 7. The other four are below.

| # | Rule | Category | Evidence | Needs | Status |
|---|---|---|---|---|---|
| 51 | Reference-selector / picker XPath that reads rows the current role cannot read under entity access (e.g. through `System.UserRoles` or an account association) | security | #169: a reassign picker listed only the user, or nothing, in both builds | widget selectable-objects XPath; `permissions()` per entity and role (probe) | idea |
| 52 | `change` with no later `commit` in a microflow reached from a scheduled event or a workflow (no client to commit it) | correctness | #169: an escalation change was lost, found only by a timer run | `activities_for()` order and `commit` targets; callers from `scheduled_events()` / workflow refs (probe) | idea |
| 53 | `addDays`/`addHours`/`trim`/`length` on an attribute that can be empty, with no empty guard before it | correctness | #169: a null runtime error | expression text in the catalog: same blocker as row 36 | blocked: expressions not indexed (upstream) |
| 54 | Navigation profile with no logout item, or a home page whose role has no read access to its entity (CE2729) | security | #169: caught late in both builds | navigation in projection (row 12's blocker) | blocked: field unconfirmed |

Two spec-level items from the same comparison are not lint rules: legal-suffix matching on company
names, and workflow admin-centre access for an approver role.

**Stock-rule false positives.** These are not candidates. They are findings on the toolkit's own conventions. The
answer for each is in `skills/lint-that-actually-runs.md` → "Stock rules against the toolkit's own
conventions". The rules are mxcli's own, so any Starlark change waits for fixtures and a toolkit replacement rule (rollout rule 1).

| Rule | Issue | Disposition |
|---|---|---|
| QUAL004 on a `DS_` Data grid 2 datasource | #360 | baseline with reason; upstream `bug-logs/pending-github-issues/qual004-dg2-datasource-ref.md`; BUG-DRAFT-qual004-dg2-datasource |
| QUAL004 on `TEST_` helpers; CUSTOM002 on `TEST_`/`GET_`/`PRS_`/`STUB_` | #241 | CUSTOM002 `enabled: false` (user decision, recorded in `PROJECT.md`) or baseline with reason; QUAL004 baseline with reason; upstream `lint-naming-prefixes-as-options.md` |
| QUAL002 on import mappings / published REST services (MDL089) | #246 | QUAL002 per-kind options in `lint-config.yaml`; upstream `qual002-skip-mdl089-types.md` |

## Cheap extras (one afternoon each, when a batch has room)

Microflow not in a folder · non-persistent entity committed to the database · many-to-many
Expand Down Expand Up @@ -171,6 +199,8 @@ a second backlog section. Forum only to weight by incident frequency.

## History

- 2026-10-14 — Batch 7 added from #169 (rows 51–54), plus dispositions for the stock-rule false
positives in #360, #241 and #246. The 2026-09-29 inbox file for #169 was promoted here and deleted.
- 2026-10-13 — Batch 6 added from #268 / #267 (rows 49–50). Lint Batch 4 shipped them as `SEC014`
and a toolkit-owned `CONV009` (status `drafted`, 32 unit cases). First field run, mxcli 0.26.0:
SEC014 1 finding with the one external role configured, positive control 7 that a SQL replay
Expand Down
Loading
Loading