Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .claude/lint-rules/conv018_module_folder_organization.star
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ FOLDERABLE_KINDS = [
"MENU",
"PAGE_TEMPLATE",
"SCHEDULED_EVENT",
"QUEUE",
"TASK_QUEUE",
"REGULAR_EXPRESSION",
"DATA_TRANSFORMER",
"WORKFLOW",
Expand All @@ -81,7 +81,7 @@ FOLDERABLE_KINDS = [
"KNOWLEDGE_BASE",
"CONSUMED_MCP_SERVICE",
"DATABASE_CONNECTION",
"REST_CLIENT",
"CONSUMED_REST_SERVICE",
"PUBLISHED_REST_SERVICE",
]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "cmd/mxcli", "date": "2026-10-12", "symptom": "`mxcli test --local` hangs indefinitely on Windows after the tests finish, when mxbuild starts a new Gradle daemon — no results, no JUnit file, no error; a run that reuses an idle daemon passes, and killing only the orphaned daemon unblocks mxcli (#1396). `mx sync-java-dependencies` (run --local) has the same shape", "cause": "`mxbuild --serve` and `mx sync-java-dependencies` write to a `syncBuffer`, so exec.Cmd creates a pipe and Wait blocks until every holder of its write end closes it. A freshly started Gradle daemon inherits that end and outlives mxbuild; the tree kill (taskkill /T, or the POSIX group signal) cannot reach a process that left the tree/group, and `ServeServer.Stop` runs before results are printed", "file": "`cmd/mxcli/docker/mxserve.go` (`newServeCmd`, `orphanPipeWaitDelay`), `cmd/mxcli/docker/javadeps.go` (`SyncJavaDependencies` treats `exec.ErrWaitDelay` as success — mx's own exit status wins)", "insight": "`cmd.WaitDelay` is the backstop for EVERY exec.Cmd whose child can spawn Gradle and whose output is not an *os.File, not only the watchdogged one-shot builds (sibling finding 2026-10-11): a tree kill bounds the tree, WaitDelay bounds what escaped it. The delay starts only after the process exits, so it cannot cut a live build short. The discriminating detail in the report was 'only when no idle daemon can be reused' — a reused daemon never held this run's pipe. Reproduces on Linux with a fake mx that starts `setsid sleep 30 &` (out of the process group, like the escaped daemon); revert proof: without WaitDelay both tests block past their 15s guard", "refs": ["mendixlabs/mxcli#1396"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/backend", "date": "2026-10-12", "refs": ["mendixlabs/mxcli#1388"], "symptom": "ALTER SNIPPET/PAGE could not add a navigation list item: `insert into navList1 { item \u2026 }` failed with \"failed to insert: failed to build widgets: failed to build widget : item must be a direct child of navigationlist\", and `insert after t1 { \u2026 }` with t1 inside an existing item failed with `failed to resolve snippet target: widget \"t1\" not found`; the only workaround was REPLACE of the whole list, retyping every item", "cause": "Two gaps of one shape: the INSERT built every node as a standalone widget, and the builder refuses a lone `item` (it is only built inside a navigationlist); and the mutator's lookup/scope/data-source walks descended into Widgets, TabPages, ControlBar.Items, \u2026 but never a NavigationList's Items, so nothing inside an item was addressable", "file": "`mdl/backend/pagemutator/navlist.go` (InsertNavigationListItems), `mdl/backend/pagemutator/mutator.go` (findInWidgetChildren, collectWidgetScopeInChildren, findNearestDSInChildren), `mdl/executor/cmd_alter_page.go` (allNavigationListItems routing), `mdl/backend/mutation.go`", "insight": "Every non-widget child list (TabPages #1215, ListView Templates, DataGrid2 columns, now NavigationList Items) needs the same three things: an executor branch before buildWidgetsFromAST, a dedicated mutator insert that wraps the children in a throwaway parent and serializes it so they get CREATE's exact shape, and a descent in all three tree walks (find, scope, nearest data source) \u2014 grep the TabPages lines in mutator.go to find every walk at once. The ALTERed snippet's NDSL dump is identical to one CREATEd with both items (the cheapest proof of shape), and mx check 11.12.1 is clean. Items carry no Name (#1373), so BEFORE/AFTER an item is not offered: `insert after t1 { item }` is refused naming the INTO form rather than guessing it meant 'after the item holding t1'. Item names as an addressing feature would need a derived/positional address (cf. layoutContainer.top), not a stored Name."}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-12", "refs": ["mendixlabs/mxcli#1388"], "symptom": "describe of a navigation list item with a CSS class printed `item (Action: \u2026, ButtonStyle: nav-orders)` \u2014 not an item property, and unparseable unquoted (`nav-orders` reads as a subtraction: \"extraneous input '{' expecting {',', ')'}\") \u2014 and CREATE wrote an empty Forms$Appearance whatever the item said, so a styled item lost its class on describe \u2192 exec", "cause": "parseNavigationListItems copied Appearance.Class into rawWidget.ButtonStyle and the navigationlist emitter printed it as ButtonStyle; pages.NavigationListItem had no appearance fields, so buildNavigationListItemV3 had nowhere to put Class/Style and navListItemToGen hard-coded newAppearance(\"\", \"\", \"\", nil)", "file": "`mdl/executor/cmd_pages_describe_parse.go` (parseNavigationListItems), `mdl/executor/cmd_pages_describe_output.go` (navigationlist item header), `mdl/executor/cmd_pages_builder_v3_widgets.go` (buildNavigationListItemV3), `mdl/backend/modelsdk/widget_write.go` (navListItemToGen), `sdk/pages/pages_widgets_action.go`, `mdl/executor/cmd_page_wireframe.go`", "insight": "An item is not a pages.Widget, so applyWidgetAppearance never reached it and every appearance property had to be threaded by hand \u2014 check that path first whenever a non-widget child (item, tab page, template) loses a property. Every Studio Pro item measured (PedApp Grid_WithNavigation, WidgetDemo_Showcase) stores the same Forms$Appearance as a widget (Class, DesignProperties, DynamicClasses, Style), so no new shape was needed. The control that settles it is a describe \u2192 exec round trip on a styled item: the pre-fix describe did not even parse, the fixed one re-executes as \"Unchanged\". Design properties on an item are still not printed or written (theme key for NavigationListItem unmeasured)."}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/catalog", "date": "2026-10-12", "symptom": "After the document types took Studio Pro's names (ako/mxcli#755, R10), \"mxcli describe --help and the catalog.db still use the old names\": the help listed restclient / odataclient / odataservice / queue / projectsecurity / model, and the catalog exposed REST_CLIENTS, REST_OPERATIONS, ODATA_CLIENTS, ODATA_SERVICES, QUEUES with ObjectType REST_CLIENT / ODATA_CLIENT / ODATA_SERVICE / QUEUE", "cause": "The R10 rename was done on the MDL grammar and describe output only. The cobra describe command keeps its own type table, help text, error hint and auto-detect maps (objectTypeToDescribe, unitTypeToDescribe), and the catalog's view names and objects.ObjectType literals are a second vocabulary nobody migrated", "file": "`cmd/mxcli/cmd_describe.go`, `mdl/catalog/tables.go` (canonical views + `LegacyTableAliases`/`legacyAliasView`, objects view, schema 24), `mdl/catalog/catalog.go` (`Tables()`), consumers in `mdl/executor/describe_auto.go`, `cmd/mxcli/lsp_completion.go`, `.claude/lint-rules/conv018_module_folder_organization.star`", "insight": "A language rename has more vocabularies than the grammar: grep the OLD spelling in every form it takes — `rest client`, `restclient`, `REST_CLIENT`, `rest_clients` — not just the keyword, since the CLI subcommand table and catalog SQL never pass through the parser and the deprecation registry cannot see them. Table names can keep an alias (a `CREATE VIEW old AS SELECT * FROM new`, exempted from TestTables_CoversAllViews via LegacyTableAliases); ObjectType literal values cannot, so a user query filtering on the old value silently returns zero rows — keep the old keys in every Go map that reads ObjectType (a pre-bump cache still holds them) and say so in the docs. Renaming a view needs a CatalogSchemaVersion bump: views are CREATE VIEW IF NOT EXISTS, so a cached catalog keeps the old objects view. Repro mdl-examples/bug-tests/1395-studio-pro-document-names-catalog.mdl; end-to-end on testdata/testapp-views: OBJECTS reports PUBLISHED_ODATA_SERVICE, CATALOG.ODATA_SERVICES still answers, and `describe MyFirstModule.CarOdataApi` auto-detects through the new value. Issue mendixlabs/mxcli#1395", "refs": ["mendixlabs/mxcli#1395", "ako/mxcli#755"]}
34 changes: 24 additions & 10 deletions .claude/skills/mendix/alter-page/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ description: "Modify an existing page or snippet's widget tree in place with ALT
|---|---|
| 28-31 | Overview |
| 32-56 | When to Use |
| 57-106 | Syntax |
| 107-446 | Operations |
| 447-525 | Examples |
| 526-616 | DataGrid 2 columns: how to address them, and what you can set |
| 617-628 | Common Mistakes |
| 629-650 | Limitations — prefer binding at page creation (ledger finding #45) |
| 651-658 | Validation Checklist |
| 659-668 | Related Commands |
| 669-673 | Related Skills |
| 57-107 | Syntax |
| 108-460 | Operations |
| 461-539 | Examples |
| 540-630 | DataGrid 2 columns: how to address them, and what you can set |
| 631-642 | Common Mistakes |
| 643-664 | Limitations — prefer binding at page creation (ledger finding #45) |
| 665-672 | Validation Checklist |
| 673-682 | Related Commands |
| 683-687 | Related Skills |

<!-- /skill-index -->
# ALTER PAGE / ALTER SNIPPET - Modify Existing Pages and Snippets
Expand Down Expand Up @@ -83,7 +83,8 @@ alter page Module.PageName {
```

A `<target>` on a page is a widget name, a DataGrid 2 column `grid column(Attr)`
(or `grid column('Caption')`), or a layout region `layoutContainer.top`. Properties go in parentheses with `:`, exactly as in
(or `grid column('Caption')`), a navigation list item `nav item(t1)` /
`nav item('Text')` / `nav item@n`, or a layout region `layoutContainer.top`. Properties go in parentheses with `:`, exactly as in
`create page`. The older spellings `set Key = value on w`, `set Key: value`
(no parentheses) and `drop widget w` still run, and warn with MDL-DEPR101,
MDL-DEPR102 and MDL-DEPR103 — write the form above.
Expand Down Expand Up @@ -321,6 +322,19 @@ page cannot go next to an ordinary widget or inside another tab page, and one in
cannot mix tab pages and widgets. Dropping or reordering tab pages still needs
`create or modify page`.

**Navigation list items:** `insert into <navigationlist> { item … }` appends an item
and leaves the others untouched. An item has no name (Studio Pro stores none), so it
is addressed like a DataGrid 2 column — by what it holds or where it is:
`nav item(t1)` (the item holding widget `t1`), `nav item('Home')` (the item showing
that text), `nav item@2` (the second). `@n` also picks one of several content
matches; an ambiguous address is refused and a miss lists every item's addresses.
Prefer the content forms — a position shifts when an item is inserted before it.
`insert before|after <item> { item … }`, `replace <item> with { item … }`,
`drop <item>`, `set (Action: …) on <item>` and `insert into <item> { widgets }` all
work; widgets never go next to an item. An item takes `Class`, `Style` and
`DynamicClasses` like a widget: `item (Action: …, Class: 'nav-home') { … }`, or
`set (Class: 'nav-home') on navList1 item@1`.

**The context comes from the nearest enclosing data source, whatever kind it is**
— a database or association source, a microflow/nanoflow source (the entity is
the flow's return type), or `datasource: selection <list>`, which takes the
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/mendix/browse-integrations/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,13 @@ where ee.Id IS null;

-- All REST operations across all consumed services
select ServiceQualifiedName, HttpMethod, path, Name
from CATALOG.REST_OPERATIONS
from CATALOG.CONSUMED_REST_OPERATIONS
ORDER by ServiceQualifiedName, path;

-- Cross-cutting: all integration services in a module
select ObjectType, QualifiedName
from CATALOG.OBJECTS
where ObjectType in ('ODATA_CLIENT', 'REST_CLIENT', 'ODATA_SERVICE',
where ObjectType in ('CONSUMED_ODATA_SERVICE', 'CONSUMED_REST_SERVICE', 'PUBLISHED_ODATA_SERVICE',
'PUBLISHED_REST_SERVICE', 'BUSINESS_EVENT_SERVICE', 'DATABASE_CONNECTION')
and ModuleName = 'Integration';
```
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/mendix/scheduled-events-and-queues/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ select QualifiedName, RepeatDescription, Microflow
from CATALOG.SCHEDULED_EVENTS
where Enabled = 1 and IntervalSeconds < 60;

select QualifiedName, Parallelism, ClusterWide from CATALOG.QUEUES;
select QualifiedName, Parallelism, ClusterWide from CATALOG.TASK_QUEUES;
```

A scheduled event counts as a caller of the microflow it runs, so
Expand All @@ -328,7 +328,7 @@ Starlark lint rules can iterate both: `scheduled_events()` yields

## Scheduled events — Mendix's cron (LIST/DESCRIBE/CREATE [OR MODIFY]/DROP). `Repeat:` names one of the eight `ScheduledEvents$*Schedule` variants and only that variant's fields are accepted; a field from another repeat is refused by `mxcli check` (MDL-SCHED01) and by exec, which call the same function. The document shape is pinned by re-serializing three whole Studio Pro-authored events (Workflow Commons 4.11.0, OIDC SSO 4.6.0, SAML 4.2.1) element by element — `modelsdk/gen` is **wrong** about two properties here

the integers are stored as int64 (gen says int32, the #585 mismatch) and `StartDateTime` is a BSON datetime (gen says string), so both engines share one raw-BSON codec in `mdl/scheduledevents`. `Interval`/`IntervalType` are legacy siblings of `Schedule` that Studio Pro writes and does not keep in sync — derived on CREATE, carried through untouched on MODIFY. Only the Day and Hour variants have a Studio Pro reference; the other six are metamodel-derived and verified to load. Both are in the catalog (`CATALOG.SCHEDULED_EVENTS`, `CATALOG.QUEUES`) and a scheduled event emits a `schedule` edge into `CATALOG.REFS` — without it a microflow run only by a scheduled event was reported as dead by `list callers`, `GRAPH_DEAD_ASSETS` and lint rule QUAL004.
the integers are stored as int64 (gen says int32, the #585 mismatch) and `StartDateTime` is a BSON datetime (gen says string), so both engines share one raw-BSON codec in `mdl/scheduledevents`. `Interval`/`IntervalType` are legacy siblings of `Schedule` that Studio Pro writes and does not keep in sync — derived on CREATE, carried through untouched on MODIFY. Only the Day and Hour variants have a Studio Pro reference; the other six are metamodel-derived and verified to load. Both are in the catalog (`CATALOG.SCHEDULED_EVENTS`, `CATALOG.TASK_QUEUES`) and a scheduled event emits a `schedule` edge into `CATALOG.REFS` — without it a microflow run only by a scheduled event was reported as dead by `list callers`, `GRAPH_DEAD_ASSETS` and lint rule QUAL004.

## Task queues (LIST/DESCRIBE/CREATE [OR MODIFY]/DROP TASK QUEUE). `Config.ParallelismExpression` is a **string** and the sibling int32 `Parallelism` is not written — matching all four Studio Pro queues in Business Events 3.12.1. Binding a *call* to a queue is not yet authorable, so `CREATE OR REPLACE|MODIFY MICROFLOW` is **refused** when the stored microflow has a queued call (guard-don't-drop, ADR-0005)

Expand Down
Loading
Loading