Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
46a47b1
fix(check): read the same widget registry exec does
claude Sep 18, 2026
abba3d7
fix(alter page): name the route a built-in widget's SET dead-ends into
claude Sep 18, 2026
81b3e62
docs: point the #1135 follow-up at the issue that tracks it
claude Sep 18, 2026
62e1756
fix(odata): type Edm.TimeOfDay, and refuse an external action Mendix …
claude Sep 18, 2026
a75952b
docs: correct the List View design-property count — six, not three
claude Sep 18, 2026
ba0a120
fix(check): stop claiming a List View's `Editable` is dropped
claude Sep 18, 2026
ab4d379
fix(pages): a list view template must be a STRICT specialization
claude Sep 18, 2026
bc41af4
Merge pull request #513 from ako/claude/mxcli-issue-1089-9vo97s
ako Sep 18, 2026
3463674
refactor(catalog): name the refs and permissions object-type vocabula…
claude Sep 18, 2026
59db6e7
fix(skills): document the lint-rule values the catalog actually emits
claude Sep 18, 2026
728a30f
fix(check): resolve design properties on ALTER STYLING, and refuse a …
claude Sep 18, 2026
bbe1500
Merge remote-tracking branch 'origin/main' into claude/issue-1135-inv…
claude Sep 18, 2026
bdd3890
fix(microflow): refuse `raise error;` outside an ON ERROR handler (MD…
claude Sep 18, 2026
d26e19a
fix(syntax): resolve a topic however it is spelled (mendixlabs/mxcli#…
claude Sep 18, 2026
5894d18
fix(pages): write the on-click a list view and the image widgets alre…
claude Sep 18, 2026
321c10d
feat(pages): author a List View's search bar with `search by`
claude Sep 18, 2026
5b0a48a
fix(pages): refuse `search by` where it cannot be stored
claude Sep 18, 2026
5199b02
Merge pull request #508 from ako/claude/issue-1135-investigation-179ttu
ako Sep 18, 2026
23dca98
Merge pull request #516 from ako/claude/pensive-darwin-2br2t2
ako Sep 18, 2026
1a8d3fa
Merge remote-tracking branch 'origin/main' into claude/upbeat-planck-…
claude Sep 18, 2026
a274595
fix(grammar): HELP takes the topic spellings the registry prints (men…
claude Sep 18, 2026
f684860
Merge remote-tracking branch 'origin/main' into claude/mxcli-issue-10…
claude Sep 18, 2026
139fd02
Merge pull request #517 from ako/claude/upbeat-planck-qla4m6
ako Sep 18, 2026
3884a80
fix(pages): round-trip a static image, reference and all
claude Sep 18, 2026
e2d3742
Merge origin/main into claude/brave-faraday-tuo7z1
claude Sep 18, 2026
649dd40
Merge pull request #518 from ako/claude/brave-faraday-tuo7z1
ako Sep 18, 2026
34ce8df
Merge pull request #521 from ako/claude/mxcli-issue-1025-2og019
ako Sep 18, 2026
b56dd79
Merge branch 'mendixlabs:main' into main
ako Sep 18, 2026
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
3 changes: 3 additions & 0 deletions .claude/commands/mxcli-dev/review.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ proactively. Add a row after every review that surfaces something new.
| 23 | A copy-to-scaffold path renames files but not the identifiers built from the name (`@mixin mxcli-<name>-<alt>`, `@import "mxcli-<name>"`), so two artefacts collide the moment both exist — and the symptom is a rule that silently compiles to nothing | Code correctness | Assert the structural contract on the *generated* artefact, not just the shipped ones: factor the built-in's contract test into a helper and run the scaffold through it. Verify once end to end against the real toolchain and record it |
| 24 | A skill or command still instructs work into a package the repo has deleted (`sdk/mpr` test locations, a symptom table moved to `findings/*.jsonl` years prior) — the doc reads as authoritative and every instruction in it is a compile error or a no-op | Docs quality | When a package is deleted or a doc is restructured, grep `.claude/` for its name in the same PR. A deletion that leaves the guidance behind is worse than no guidance, because the reader trusts it |
| 25 | A doc or skill shows a CLI invocation nobody ran — a command name that does not exist (`mxcli dump-bson` for `mxcli bson dump`), or a flag form the parser rejects (`--compare "A" "B"` where `--compare` is a StringSlice needing `"A,B"`). Worst when copied FROM the command's own `--help`, which had the same error, so the doc looks sourced | Docs quality | Run every command a doc shows, against a real project, before committing it. If it came from `--help`, run that form too — the example in the help text is not evidence that it works |
| 26 | A clause added to a SHARED grammar rule (a datasource, a widget-property list) is written by only ONE of the constructs that rule serves — the others parse it, `exec` reports success, and DESCRIBE does not echo it back. A silent drop, often shipped by the very change that was fixing silent drops | Code correctness | Enumerate the other constructs the rule serves and RUN one. The round-trip that proved the feature on its intended target says nothing about them. Refuse it where it cannot be stored, naming the construct that can — an error, not a warning, when the metamodel decides it and no future package can make it valid |
| 27 | A metamodel-sync or list-coverage test asserts that a GAP still exists (`clickCapableInMendix["listview"]`, "a template for the list view's own entity is the base case Mendix permits") — so it passes throughout and FAILS on the correct fix, and the belief it encodes was never measured | Test coverage | Invert such a test rather than deleting it: keep the half that is still true (the metamodel really does carry the field) and flip the half that is not. When a test justifies itself by what a helper returns rather than by a measurement, treat it as a claim to check, not as evidence |
| 28 | A describe emitter added beside a shared property formatter duplicates a field the formatter already prints (`Editable: true` twice on one widget) — invisible when the round-trip only covers the page the change was written against | DESCRIBE roundtrip | Round-trip a page OTHER than the one under test, and assert occurrence COUNT (`strings.Count(out, x) != 1`), not presence. `Unchanged page` on re-exec of the describe output is the evidence that the emitted MDL rebuilds the stored document; `Check passed!` is not |

---

Expand Down
1 change: 1 addition & 0 deletions .claude/skills/fix-issue/findings/cmd-mxcli.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,4 @@
{"area": "cmd/mxcli", "date": "2026-09-17", "symptom": "`mxcli run --local --mxbuild-path /x -p app.mpr` answers `Error: unknown flag: --mxbuild-path`, while the shipped run-local skill, runlocal.go's own comment and two resolution error messages all tell the user to pass it", "cause": "The flag was never registered on `runCmd`; it exists only on the four `docker` subcommands. Everything BEHIND it was already wired \u2014 `LocalRunOptions.MxBuildPath` is declared and `ResolveMxBuildForLocal` honours it \u2014 so the gap was one missing `Flags().String` and one missing field assignment, invisible to every test because nothing exercised the command's flag set", "file": "`cmd/mxcli/cmd_run.go` (flag registration + LocalRunOptions.MxBuildPath) + `.claude/skills/mendix/run-local/SKILL.md` + `docs-site/src/tools/run-local.md`", "insight": "The interesting defect is not the missing flag, it is that **the error messages recommending it were the only documentation of it** \u2014 guidance naming an option the command does not accept is worse than no guidance, because it reads to the user as their own mistake, and on macOS it was the only advertised way out of a platform mismatch. The regression test to write is therefore not 'the flag exists' but the invariant: scan the resolution sources for `--flag` strings they tell users to pass, and assert `run` registers each one (`TestErrorGuidanceNamesAFlagThatExists`). Watch the parse test \u2014 `-p` is PERSISTENT on rootCmd, so `runCmd.Flags().Parse` rejects it with `unknown shorthand flag: 'p'` and the test fails for a reason unrelated to the fix; resolve through `rootCmd.Find` to reproduce the reporter's line honestly. Issue #1125", "refs": ["#1125", "#916", "#1122"]}
{"area": "cmd/mxcli", "date": "2026-09-17", "symptom": "`mxcli run --local` on a project with Settings > Web UI > OptimizedClient = No exits 1 after the cold build with `no rollup.config.mjs and no bundle at .../web/dist/index.js ... the build did not produce a client` \u2014 about a deployment whose client is sitting in the same directory. `mxcli docker run` works", "cause": "The client gate tested for exactly two shapes (a rollup config to run, or a bundle mxbuild already wrote) and treated everything else as a failed build. A classic (Dojo) deployment is a legitimate third shape with NEITHER: there is no bundling step for the classic client in any Mendix version. Nothing in the local loop read UseOptimizedClient, so the mode was invisible", "file": "`cmd/mxcli/docker/webclient_plan.go` (new: `planWebClient`, `isClassicWebClient`, `noWebClientError`) + `webclient.go` (`BuildWebClient`, `ensureWebClientBundle`) + `webclient_watch.go` (`StartWebClientWatch`) + `runlocal.go` (`ensureClientServed`)", "insight": "Measured on one blank 11.12.2 app built twice, changing only the setting: **mxbuild swaps which client lands in `deployment/web/` and parks the other beside it** \u2014 OptimizedClient=Yes gives `web/` the React client (+`rollup.config.mjs`) and parks Dojo in `dojo-web/`; =No gives `web/` the Dojo client (`index.html` loading `mxclientsystem/mxui/mxui.js`, no rollup config, no dist) and parks React in `react-web/` WITH its own rollup config. So detect from the DEPLOYMENT, not from the model's setting: the deployment is what gets served, the two disagree exactly when the setting has just changed, it needs no plumbing through the five call sites, and it covers MigrationMode without predicting what that mode emits. Detect on POSITIVE evidence (the entry point names its client) \u2014 inferring classic from the absence of the React shapes would make every genuinely broken deployment look classic and silently skip the bundle, which is the black screen the gate exists to prevent; keep a control test that a clientless deployment still fails. **The gate had FIVE consumers, not one**: boot, the `--watch` bundler, the post-boot re-bundle guard, and `ensureClientServed`, which probes that `/dist/index.js` is *served* \u2014 measured 404 on a classic app, so fixing only the boot moves the failure to every applied change under `--watch`. Two of them carried hand-copied duplicates of the same gate and had already drifted once (the 11.14 fix, ako/mxcli-ledger #146, landed on `BuildWebClient` only, so `run --local` worked on 11.14 and `run --local --watch` did not) \u2014 so the fix collapses them into one `planWebClient` rather than adding a third copy. Repro from Linux with no Mac and no Studio Pro: `mxcli new` an 11.12.2 app, flip `UseOptimizedClient` to `No` on `Forms$WebUIProjectSettingsPart` (note the `Forms$` prefix, not `Settings$`), build, and keep the unflipped copy as the control. Patching that BSON with a Go `map` corrupts the file \u2014 mxbuild refuses it with `Expected '$ID' as the first property of a storage object` \u2014 because map iteration loses key order; use `bson.D` throughout. Verified in a browser, not just at the gate: `mx` global present, real page content, zero console errors. Issue #1123", "refs": ["#1123", "ako/mxcli-ledger#146"]}
{"area": "cmd-mxcli", "date": "2026-09-17", "symptom": "`mxcli new --version 10.24.25` (and `mxcli setup mxbuild --version 10.24.25`) dies with `HTTP 404 from https://cdn.mendix.com/runtime/mxbuild-10.24.25.tar.gz`. Every 9.x and 10.x version probed 404s while 11.6.0/11.12.1/11.13.0 return 200 from the same host and path, which reads as 'Mendix 10 is no longer on the CDN'.", "cause": "Mendix 9 and 10 publish FOUR-part artifact names carrying a build number the release notes never mention: the release called 10.24.25 is `mxbuild-10.24.25.122571.tar.gz`. Mendix 11 publishes three parts. `MxBuildCDNURL` interpolates whatever string it is handed and nothing resolved a partial version, so a hand-typed 10.x version named no artifact at all. Project-driven paths were never affected — the MPR's `_ProductVersion` already carries all four parts (`10.24.25.122571`) and `parseVersion` takes the first three for major/minor/patch while the full string goes to the URL.", "file": "`cmd/mxcli/docker/version_resolve.go` (ResolveCDNVersion, highestBuild, CDNReleasesFor); wired at the two entry points where a user types a version, `cmd/mxcli/cmd_new.go` and `cmd/mxcli/setup.go`. Tests `cmd/mxcli/docker/version_resolve_test.go`.", "insight": "**A uniform 404 across a whole major version is evidence about the NAME, not about availability.** The conclusion drawn from it — 'Mendix 10 cannot be downloaded here' — blocked a verification for an entire session, and the fix was one listing call: the CDN is an S3 bucket that answers ListObjectsV2 (`?list-type=2&prefix=runtime/mxbuild-10.24.`), so what exists is enumerable rather than guessable. When a probe fails identically for every input in a class, question the query before concluding the class is empty. Three traps in the resolution itself, each a test: the `.sha256` sidecar beside every archive must not be picked as an artifact; the prefix needs its trailing dot or `10.24.2` swallows `10.24.20`..`10.24.26`; and build numbers are not zero-padded, so a text sort puts 99999 above 122571 and 10.24.9 above 10.24.26. Resolve at the entry point and thread the RESOLVED string onward — `mxcli new` checks the created project's stamp against the requested version, and `mx create-project` stamps four parts, so resolving late would fail that postcondition.", "refs": ["#1121"]}
{"area": "cmd/mxcli", "date": "2026-09-18", "symptom": "mendixlabs/mxcli#1025: `mxcli syntax` advertises `mxcli syntax workflow user-task targeting` in its own help and answers `Unknown topic: workflow user-task targeting`. Same for `workflow user-task` and `workflow parallel-split`, all of which `mxcli syntax workflow` lists as sub-topics; `--json` was the only route that reached them.", "cause": "The CLI built its path with `strings.Join(args, \".\")` and never split an argument, so a topic handed over as ONE string — a quoted copy-paste, a tool wrapper, `sh -c` — became the path `workflow user-task targeting`, which matches nothing. The REPL's `help` had resolved multi-word topics since it was written (`resolveHelpPath`, greedy hyphen-joining): one question, two answers, and the CLI held the weaker copy. The #955 segment-match fallback could not save it either — it passed the DOTTED path to `BySegmentMatch`, and no segment contains a '.', so that fallback was silently dead for every multi-word query.", "file": "cmd/mxcli/syntax/topic.go (new: Lookup, topicWords, resolvePath), cmd/mxcli/help.go, mdl/executor/cmd_misc.go (resolveHelpPath deleted), mdl/grammar/domains/MDLSettings.g4 (helpStatement, helpTopicWord), mdl/visitor/visitor_query.go (ExitHelpStatement); tests cmd/mxcli/cmd_syntax_test.go, cmd/mxcli/syntax/topic_test.go, mdl/executor/cmd_misc_test.go, mdl/visitor/visitor_help_topic_test.go; example mdl-examples/bug-tests/syntax-1025-topic-drilldown.mdl", "insight": "**The spaces in the reported error message were the whole diagnosis, and reading them as a paraphrase cost an hour.** The command prints the path it built, and the CLI joins on '.', so `Unknown topic: workflow user-task targeting` cannot come from the command as documented — it can only come from the topic arriving as a single argument. Every line of the report follows from that and nothing else does: `syntax workflow` works (one word), `--json` works (the flag is not part of the topic), the three multi-word forms fail. Take a quoted error message literally, character for character, before assuming the reporter retyped it. **The reported version is downloadable and settles it in one run**: `mxcli setup mxcli`'s own URL shape (`releases/download/<tag>/mxcli-linux-amd64`, NOT the goreleaser `_Linux_x86_64.tar.gz` that 404s) fetched v0.20.0, where the unquoted command works and the quoted one reproduces the message verbatim — so 'fixed since' and 'never broken' were both wrong. **The guard that matters is not the three cases from the report** but `TestEveryRegisteredPathIsReachableBySpelling`: every registered path, tried dotted, as separate arguments, and as one string. The registry prints dotted paths and then tells the reader to drill down with words, so a spelling that does not resolve is the command contradicting its own output; a per-case test would have passed the day someone added a topic with a new shape. Control: stub the whitespace split in `topicWords` and it fails with the reported path, spaces and all. **The grammar half has a trap the CLI half does not, and only the EXISTING suite caught it.** `helpStatement: IDENTIFIER (identifierOrKeyword)*` is the grammar's catch-all — a statement that is just an identifier and some words — so whatever it can swallow, it swallows from the statement that should have had it. Widening it to `(DOT? helpTopicWord)*` to take `help workflow.user-task` made `Sec.ApiUser` a complete statement of its own, and `create module role Sec.ApiUser` then parsed, WITH NO PARSE ERROR, as CREATE MODULE (named \"role\") followed by a help topic — two statements, wrong types, six unrelated security tests red. `(helpTopicWord (DOT? helpTopicWord)*)?` — a topic word before any dot — leaves `.ApiUser` unconsumable and restores the old disambiguation. Bisect a grammar regression by SHAPE, not by reading the ATN: adding the unused rule alone was clean, the hyphen alone was clean, the leading optional DOT was the whole of it, and three regenerations said so in about a minute. **When widening a permissive rule, the test to add is not for the new spelling but for what the rule must still NOT swallow** (TestHelpRuleDoesNotSwallowATrailingQualifiedName).", "refs": ["mendixlabs/mxcli#1025", "#955"]}
Loading
Loading