Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
0d769c2
fix(check): flag an enumeration decision with no empty outcome (MDL-W…
claude Sep 8, 2026
75acb68
feat(catalog): index offline sync configs, and make a synced entity a…
ako Sep 9, 2026
d2f6719
fix(check): report a module role written without its module (MDL-GRAN…
claude Sep 9, 2026
e2d92f2
feat(entities): say which roles cannot see an attribute just added
claude Sep 9, 2026
39436a6
fix(widgets): lift the editor hide-rules describe was missing, conjun…
claude Sep 9, 2026
ee25282
Merge remote-tracking branch 'origin/main' into claude/banking-app-fe…
claude Sep 9, 2026
42fed99
Merge pull request #426 from ako/feat/offline-sync-catalog
ako Sep 9, 2026
e6596c5
feat(navigation): author ON SYNC ERROR THROW|CONTINUE
ako Sep 9, 2026
8db3cb5
fix(widgets): never drop a visibility rule the older vocabulary alrea…
claude Sep 9, 2026
91d0c77
Merge remote-tracking branch 'origin/main' into claude/banking-app-fe…
claude Sep 9, 2026
2710287
Merge pull request #427 from ako/claude/banking-app-feedback-do04dy
ako Sep 9, 2026
a7a17cf
Merge pull request #428 from ako/feat/offline-sync-throw-error
ako Sep 9, 2026
af00b9e
Merge remote-tracking branch 'origin/main' into claude/mxcli-findings…
claude Sep 9, 2026
b6b92a2
Merge pull request #429 from ako/claude/mxcli-findings-nnl181
ako Sep 9, 2026
45d8ff5
feat(check): resolve ALTER PAGE SET against the stored document
claude Sep 9, 2026
d7ec1de
fix(widgets): read a chained ternary's branch condition, not the whol…
claude Sep 9, 2026
1ce0f9b
Merge remote-tracking branch 'origin/main' into claude/banking-app-fe…
claude Sep 9, 2026
820b63f
Merge pull request #430 from ako/claude/mxcli-unit-test-perf-n7ggx8
ako Sep 9, 2026
5e2f445
Merge remote-tracking branch 'origin/main' into claude/banking-app-fe…
claude Sep 9, 2026
383d64f
Merge pull request #431 from ako/claude/banking-app-feedback-do04dy
ako Sep 9, 2026
039a1f1
feat(modelsdk): write SOAP call web service on the codec engine
claude Sep 9, 2026
66c24aa
fix(microflow): stop DESCRIBE dropping an activity's error handler (m…
claude Sep 9, 2026
ba1bf6b
fix(check): report a duplicate CREATE MODULE ROLE against the project
claude Sep 9, 2026
c99eab6
test(gate): run the legacy engine nightly, not on every push
claude Sep 10, 2026
185305d
fix(ci): carry the engine set in the step name, and correct a claim
claude Sep 10, 2026
6710094
fix(microflow): keep the nanoflow error-handling default (mendixlabs/…
claude Sep 10, 2026
0255fe2
Merge pull request #432 from ako/claude/mxbuild-diagnostics-spike-emta6h
ako Sep 10, 2026
2442623
Merge pull request #433 from ako/claude/mxcli-unit-test-perf-n7ggx8
ako Sep 10, 2026
eb6ca39
build(deps-dev): Bump svgo
dependabot[bot] Sep 10, 2026
cd7dca8
build(deps): Bump js-yaml
dependabot[bot] Sep 10, 2026
214303e
Merge remote-tracking branch 'origin/main' into claude/mxcli-findings…
claude Sep 10, 2026
bc9db46
Merge pull request #435 from ako/dependabot/npm_and_yarn/dot-claude/s…
ako Sep 10, 2026
ffdb488
Merge pull request #436 from ako/dependabot/npm_and_yarn/dot-claude/s…
ako Sep 10, 2026
59faeae
Merge pull request #434 from ako/claude/mxcli-findings-nnl181
ako Sep 10, 2026
ec7ef1e
fix(catalog): never write a narrower catalog over a richer cache
claude Sep 10, 2026
b31c499
Merge origin/main into claude/gallant-curie-4vivo0
claude Sep 10, 2026
afa4742
fix(microflow): keep an annotation's identity through a round trip (m…
claude Sep 10, 2026
ee4180b
Merge pull request #437 from ako/claude/gallant-curie-4vivo0
ako Sep 11, 2026
5a6ee01
Merge pull request #438 from ako/claude/mxbuild-diagnostics-spike-emta6h
ako Sep 11, 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
6 changes: 6 additions & 0 deletions .claude/commands/mendix/refresh-catalog.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ REFRESH CATALOG FULL FORCE;
- Use FULL mode before using SEARCH command
- Use SOURCE mode for searching MDL definitions

The cache's mode is sticky. Once a project has a FULL or SOURCE cache, a plain
`REFRESH CATALOG` rebuilds at that level rather than dropping to FAST, and a
command that needs less (`mxcli check -p`, `show structure`, `describe`) never
replaces it with a narrower one. To go back to a cheaper level, delete
`.mxcli/catalog.db` and refresh.

## Example Queries After Refresh

```sql
Expand Down
2 changes: 2 additions & 0 deletions .claude/skills/fix-issue/findings/mdl-backend.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,5 @@
{"area": "mdl/backend", "date": "2026-09-08", "symptom": "A property Studio Pro writes on an offline entity config (CompatibilityMode) was read from the model and silently discarded, so any future write path would have dropped it with no error and no mx check failure", "cause": "types.NavOfflineEntity carried three of the four properties Studio Pro actually writes. TestFieldCountDrift, which exists to catch exactly this on hand-copied structs, did not list NavOfflineEntity or NavigationProfile — so adding the field left the guard passing vacuously", "file": "`mdl/types/navigation.go`, `mdl/backend/mpr/convert.go`, `mdl/backend/mpr/convert_roundtrip_test.go`", "insight": "A drift guard is only worth what its list covers, and a guard that passes on a struct it does not know about is worse than none — it reads as coverage. Check the guard names your type before trusting a green run. Also: measure which properties are actually WRITTEN before deciding what to carry — gen declared six here and the reference document had four, with DownloadMode and ShouldDownload occurring zero times, so the risk was inverted from the expected one (writing a property Studio Pro fills in on load, not dropping one)", "refs": ["ako/TestApp", "ako/mxcli#413"]}
{"area": "mdl/backend", "date": "2026-09-08", "symptom": "An offline navigation profile authored by mxcli builds, routes and installs as a PWA, and shows an empty app — every gate green", "cause": "MDL had no syntax for offline synchronization, so a created offline profile got an empty OfflineEntityConfigs list. A Mendix offline profile downloads nothing until each entity has a sync mode; `mx check` reports 0 errors either way because an empty list is valid", "file": "`mdl/grammar/MDLParser.g4` (navSyncDef), `mdl/backend/modelsdk/navigation_write.go`, `sdk/mpr/writer_navigation.go`", "insight": "Creating a document kind is not the same as being able to configure it, and the gap is invisible to every static check — the symptom is an empty screen at runtime. When adding a profile/document kind, ask what makes it DO anything, not just what makes it exist. The write is an overlay keyed by entity so CompatibilityMode (stored, unauthorable) survives; building the element from the spec alone would clear it silently, the access-rule defect again", "refs": ["ako/TestApp", "PROPOSAL_offline_sync_configuration.md"]}
{"area": "mdl/backend", "date": "2026-09-08", "symptom": "`alter page P { set PageSize = 10 on <datagrid2> }` errors `pluggable property \"PageSize\" not found` on a grid that `create page \u2026 (PageSize: 20)` had just written and the app really pages at. `mxcli check --references` passes the script, so it fails only at exec, after earlier statements have landed; DESCRIBE PAGE prints the same capitalised `PageSize:`, so describe \u2192 edit \u2192 exec produced a script mxcli refused to run", "cause": "A pluggable property key is lowerCamel in the widget template (`pageSize`). CREATE resolves the author's spelling case-INsensitively (widget engine `lookupProperty`, and `WidgetV3.GetStringProp` before it); ALTER went through `setPluggableWidgetPropertyMut`, which compared the template key byte-for-byte, so only the exact `pageSize` worked. Direct sequel to Findings #1 (2026-07-27), which fixed the same class for FIRST-CLASS props and deliberately left the pluggable fallback case-sensitive with the comment 'template keys must match the template exactly'", "file": "`mdl/backend/pagemutator/mutator.go` (`setPluggableWidgetPropertyMut`)", "insight": "`strings.EqualFold` against the widget's own PropertyTypes. **The disproven belief is the reusable part**: keys are STORED case-sensitively, which is not a reason to MATCH them that way \u2014 the resolver searches one object type's PropertyTypes, and across every shipped template and definition that scope holds no two keys differing only in case (96 scopes, 1208 keys, 0 collisions). Measure the ambiguity before assuming it; here there was none, and the assumption cost a whole verb. **Cheapest localiser**: run the failing statement with the template's own casing \u2014 `set pageSize` succeeded where `set PageSize` failed, in ONE measurement, on the same widget in the same project. Both engines share `pagemutator`, so an engine split says nothing here (verified: modelsdk and legacy both fixed by the one change). Tests `TestSetPluggableProperty_MatchesTemplateKeyRegardlessOfCase` (+ typo-still-errors control, + `TestPluggablePropertyKeysAreUniqueIgnoringCase` pinning the no-collision argument); repro `mdl-examples/bug-tests/alter-page-pluggable-property-casing.mdl`; verified 0 errors on `mx check` 11.13.0. Two reporter claims did NOT hold: `describe page` DOES emit PageSize, but only when it differs from the widget default 20 (deliberate, so describe round-trips) \u2014 at the default it is omitted, which reads as 'describe cannot show it'. Still open and separate: `check --references` does not resolve pluggable property names at all, so a genuine typo (`PagSize`) still checks clean and fails at exec", "refs": ["mendixlabs/mxcli#1069"]}
{"area": "mdl/backend", "date": "2026-09-09", "symptom": "A control that should have proven a guard was load-bearing PASSED with the guard removed — the test could not distinguish a correct writer from one that reset the property on every write", "cause": "The fixture stored `false` for a boolean property, and false is also the zero value. A writer that ignored the spec entirely wrote false; the correct writer preserved false. Identical output, so the assertion held either way", "file": "`mdl/backend/modelsdk/navigation_throw_sync_test.go`", "insight": "For a BOOLEAN property, a preservation test must exercise BOTH stored values — the non-zero one is the only case that can fail. This is the second time in one feature: CompatibilityMode needed a synthetic `true` because all seven reference configs carry false. The generalisation: when every real document agrees on a value, the fixture drawn from real documents cannot test preservation, and a synthetic counter-case is not optional. The tell is a control that fails to fail — if stubbing the guard leaves the suite green, the test is measuring nothing, and that is worse than no test because it reads as coverage", "refs": ["ako/mxcli#413", "ThrowPartialSyncError"]}
{"area": "mdl/backend", "date": "2026-09-09", "symptom": "`call web service` (legacy SOAP) on the DEFAULT engine: `mxcli exec 06b-soap-examples.mdl` reported success on all three microflows and `mx check` (11.13.0) then failed the project with `[CE0008] \"No action defined.\" at Action activity 'Activity'` plus two `[CE0109] \"Undefined variable 'Root'.\"`. Only reachable by rerunning with MXCLI_ENGINE=legacy, which is why legacy was still the documented fallback", "cause": "The codec engine READ the action (`actionFromGen` \u2192 `*microflows.WebServiceCallAction`, with a raw fallback) but `microflowActionToGen` had no case for it, so it hit `default: return nil` and the enclosing ActionActivity serialized with no action at all. The #850 shape: a missing WRITE case is not an unsupported feature, it is a silent drop that exec reports as success. The CE0109s are knock-on \u2014 the dropped action never bound $Root", "file": "`mdl/backend/modelsdk/microflow_webservice_write.go` (new), `microflow_write.go` (switch case)", "insight": "**Mirror the legacy serializer, and prove it by diffing the two engines' documents \u2014 do not re-derive the shape from the metamodel.** There is no Studio Pro-authored SOAP document in this repo, so legacy's output is the only reference that exists and is also what users' projects already contain. Method: exec the same script on each engine, `mxcli bson dump` both, normalise the random $IDs, diff. Three discrepancies fell out that no amount of reading would have shown, all in how the codec emits NULLS and MARKERS: (1) a Part property with no child encodes to nil and the encoder then SKIPS the key (`if val != nil`), so an unset part is an ABSENT key, never a null one \u2014 carry the null as a primitive `bson.Null{}` value instead, which marshals in place; (2) `codec.TypeDefaults.NullFields` does emit the key but APPENDS it after every property, so it cannot reproduce alphabetical key order; (3) both NullFields and list markers are registered per `$Type` and several types are SHARED between writers \u2014 `Microflows$HttpConfiguration` needs HttpHeaderEntries marker 3 for SOAP and 2 for REST, and legacy writes CustomLocationTemplate as null for SOAP but omits it for REST, so a global registration would have silently changed the REST path. Write those explicitly per call site. (The package already carries one such collision: `Microflows$HttpHeaderEntry` is registered 2 in microflow_write.go and 3 in odata_write.go, decided by file order.) Verified: the two engines' CallWebServiceAction documents are now identical key-for-key and value-for-value; `mx check` goes 3 structural errors \u2192 0, leaving only the script's 4 deliberate CE1613 dangling refs, which is exactly legacy's output. Revert control: removing the switch case fails all six unit tests with the CE0008 message. The doctype engineScriptSkip for modelsdk/06b was removed and the script now runs on BOTH engines", "refs": []}
Loading
Loading