Skip to content

Commit 9899bda

Browse files
authored
Merge branch 'main' into fix/dset-silent-failure
2 parents 34d7a58 + 4da5973 commit 9899bda

401 files changed

Lines changed: 27649 additions & 27633 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/debug-bson.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ Use when encountering:
2525
### Step 1: Reproduce the Error
2626

2727
```bash
28-
# Create a page via MDL
28+
# create a page via MDL
2929
./bin/mxcli exec script.mdl -p /path/to/app.mpr
3030

31-
# Run mx check to get the error
31+
# run mx check to get the error
3232
reference/mxbuild/modeler/mx check /path/to/app.mpr
3333
```
3434

@@ -58,8 +58,8 @@ import json
5858
conn = sqlite3.connect('/path/to/app.mpr')
5959
cursor = conn.cursor()
6060

61-
# Find the document containing the widget
62-
cursor.execute("SELECT UnitData FROM Unit$ WHERE ContainmentName = 'Document' AND Name = ?", ('PageName',))
61+
# find the document containing the widget
62+
cursor.execute("select UnitData from Unit$ where ContainmentName = 'Document' and Name = ?", ('PageName',))
6363
row = cursor.fetchone()
6464
doc = bson.decode(row[0])
6565

@@ -72,7 +72,7 @@ print(json.dumps(doc, indent=2, default=str))
7272
Extract the widget's mpk to understand its schema and mode-dependent rules:
7373

7474
```bash
75-
# Find the mpk in the project's widgets folder
75+
# find the mpk in the project's widgets folder
7676
ls /path/to/project/widgets/*.mpk
7777

7878
# Extract (mpk is a ZIP archive)
@@ -81,8 +81,8 @@ cd /tmp/mpk-widget && unzip /path/to/project/widgets/com.mendix.widget.web.Datag
8181
```
8282

8383
Key files inside the mpk:
84-
- **`{Widget}.xml`** — Property schema: types, defaults, enumerations, nested objects
85-
- **`{Widget}.editorConfig.js`** — Mode-dependent visibility rules (which properties hide/show based on other values)
84+
- **`{widget}.xml`** — Property schema: types, defaults, enumerations, nested objects
85+
- **`{widget}.editorConfig.js`** — Mode-dependent visibility rules (which properties hide/show based on other values)
8686
- **`package.xml`** — Package version metadata
8787

8888
### Step 5: Read editorConfig.js for Mode Rules
@@ -108,18 +108,18 @@ Use binary search to find the exact property causing the error:
108108
# Mutation test: change a single property on a known-good widget
109109
import bson
110110

111-
# Read the working widget BSON
111+
# read the working widget BSON
112112
with open('working-widget.bson', 'rb') as f:
113113
doc = bson.decode(f.read())
114114

115-
# Change only one property value
115+
# change only one property value
116116
# ... modify the specific property ...
117117

118118
# Re-encode and write back
119119
with open('test-widget.bson', 'wb') as f:
120120
f.write(bson.encode(doc))
121121

122-
# Then insert back into the MPR and run mx check
122+
# then insert back into the MPR and run mx check
123123
```
124124

125125
### Step 7: Extract Fresh Templates
@@ -131,7 +131,7 @@ If the widget template is outdated, extract a fresh one:
131131
reference/mxbuild/modeler/mx convert -p /path/to/app.mpr
132132
reference/mxbuild/modeler/mx update-widgets /path/to/app.mpr
133133

134-
# Then extract using mxcli
134+
# then extract using mxcli
135135
./bin/mxcli extract-templates -p /path/to/app.mpr -widget "com.mendix.widget.web.datagrid.DataGrid2" -o /tmp/template.json
136136
```
137137

@@ -159,20 +159,20 @@ Three Mendix tools parse the same BSON but with **different strictness levels**:
159159
```bash
160160
# Self-diff: is the project's BSON clean?
161161
mx diff project.mpr project.mpr output.mpr
162-
# Success = all BSON matches schema. Crash = some mxunit has bad properties.
162+
# success = all BSON matches schema. Crash = some mxunit has bad properties.
163163

164-
# Cross-diff: compare baseline vs modified
164+
# cross-diff: compare baseline vs modified
165165
# 1. Extract baseline from git
166-
mkdir /tmp/baseline && cd project-dir && git archive HEAD -- *.mpr mprcontents/ | tar -x -C /tmp/baseline/
167-
# 2. Run diff (file names must match!)
166+
mkdir /tmp/baseline && cd project-dir && git archive head -- *.mpr mprcontents/ | tar -x -C /tmp/baseline/
167+
# 2. run diff (file names must match!)
168168
mx diff /tmp/baseline/App.mpr ./App.mpr /tmp/diff-output.mpr
169169
```
170170

171171
### Interpreting mx diff Output
172172

173173
**Detailed error** (when both sides have same-ID objects):
174174
```
175-
Objects with ID b6fc893f-... of type Settings$ServerConfiguration do not have the same properties.
175+
objects with ID b6fc893f-... of type settings$ServerConfiguration do not have the same properties.
176176
baseNames = ApplicationRootUrl, ConstantValues, CustomSettings, ..., Tracing;
177177
newNames = ApplicationRootUrl, ConstantValues, ...
178178
```
@@ -186,15 +186,15 @@ Sequence contains no matching element
186186

187187
### Finding the Offending mxunit File
188188

189-
Write a Go tool (or use the pattern below) to compare property keys of mxcli-written files against Studio Pro-native files of the same `$Type`:
189+
Write a Go tool (or use the pattern below) to compare property keys of mxcli-written files against Studio Pro-native files of the same `$type`:
190190

191191
```go
192-
// Walk mprcontents/, group files by $Type, compare key sets
192+
// Walk mprcontents/, group files by $type, compare key sets
193193
// Files with EXTRA keys (vs native files of same type) = the crash cause
194194
// Files with MISSING keys = also crash cause for mx diff
195195
```
196196

197-
The principle: for each `$Type`, ALL instances must have the **exact same set of non-$ property names**. Any deviation → crash.
197+
The principle: for each `$type`, ALL instances must have the **exact same set of non-$ property names**. Any deviation → crash.
198198

199199
### Version-Specific Properties
200200

@@ -229,7 +229,7 @@ Some properties only exist in certain Mendix versions. Before adding a property
229229

230230
**Symptom**: Studio Pro crashes when opening a project with `System.InvalidOperationException: Sequence contains no matching element` at `Mendix.Modeler.Storage.Mpr.MprProperty..ctor`.
231231

232-
**Root cause**: A BSON document contains a property (field name) that does not exist in the Mendix type definition for its `$Type`. Studio Pro's `MprProperty` constructor uses `First()` to look up each BSON field in the type cache, and crashes on unrecognized fields.
232+
**Root cause**: A BSON document contains a property (field name) that does not exist in the Mendix type definition for its `$type`. Studio Pro's `MprProperty` constructor uses `First()` to look up each BSON field in the type cache, and crashes on unrecognized fields.
233233

234234
**Diagnosis workflow**:
235235

@@ -242,10 +242,10 @@ type_props = defaultdict(set)
242242

243243
def walk_bson(obj, tp):
244244
if isinstance(obj, dict):
245-
t = obj.get("$Type", "")
245+
t = obj.get("$type", "")
246246
if t:
247247
for k in obj.keys():
248-
if k not in ("$Type", "$ID"):
248+
if k not in ("$type", "$ID"):
249249
tp[t].add(k)
250250
for v in obj.values():
251251
walk_bson(v, tp)
@@ -272,7 +272,7 @@ for t, props in crash_props.items():
272272

273273
3. **Extra properties = the crash cause**. The fix is to remove those fields from the writer function.
274274

275-
**Example**: `DomainModels$CrossAssociation` had `ParentConnection` and `ChildConnection` copied from `DomainModels$Association`, but these fields don't exist on `CrossAssociation`. Removing them fixed the crash.
275+
**Example**: `DomainModels$CrossAssociation` had `ParentConnection` and `ChildConnection` copied from `DomainModels$association`, but these fields don't exist on `CrossAssociation`. Removing them fixed the crash.
276276

277277
**Key principle**: When copying serialization code between similar types (e.g., Association → CrossAssociation), always verify which fields belong to each type by checking a baseline project's BSON.
278278

@@ -282,7 +282,7 @@ for t, props in crash_props.items():
282282

283283
**Root cause**: Two variants:
284284

285-
1. **Association stored as Attribute**: In `ChangeActionItem` BSON, an association name was written to the `Attribute` field instead of the `Association` field. Check the executor code that builds `MemberChange` — it must query the domain model to distinguish associations from attributes.
285+
1. **Association stored as Attribute**: In `ChangeActionItem` BSON, an association name was written to the `attribute` field instead of the `association` field. Check the executor code that builds `MemberChange` — it must query the domain model to distinguish associations from attributes.
286286

287287
2. **Entity treated as Enumeration**: In `CreateVariableAction` BSON, an entity qualified name was used as `DataTypes$EnumerationType` instead of `DataTypes$ObjectType`. Check `buildDataType()` in the visitor — bare qualified names default to `TypeEnumeration` and need catalog-based disambiguation.
288288

.claude/skills/design-mdl-syntax.md

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ When principles conflict, higher-priority ones win.
1818

1919
MDL targets citizen developers and business analysts, not software engineers. Statements should read as natural English sentences.
2020

21-
- Use keyword words (`FROM`, `WHERE`, `IN`), not symbols (`->`, `|>`, `=>`)
22-
- Spell out full words (`MICROFLOW`, `ASSOCIATION`), not abbreviations (`MF`, `ASSOC`)
23-
- Use prepositions to clarify relationships: `GRANT READ ON Entity TO Role`
21+
- Use keyword words (`from`, `where`, `in`), not symbols (`->`, `|>`, `=>`)
22+
- Spell out full words (`microflow`, `association`), not abbreviations (`MF`, `ASSOC`)
23+
- Use prepositions to clarify relationships: `grant read on entity to role`
2424

2525
**Test**: Read it aloud. A business analyst should understand on first hearing.
2626

@@ -30,34 +30,34 @@ Reuse existing patterns. Never create a second syntax for the same concept.
3030

3131
| Operation | Pattern | Example |
3232
|-----------|---------|---------|
33-
| Create | `CREATE [MODIFIERS] <TYPE> Module.Name (...)` | `CREATE PERSISTENT ENTITY Shop.Product (...)` |
34-
| Modify | `ALTER <TYPE> Module.Name <OPERATION>` | `ALTER ENTITY Shop.Product ADD (...)` |
35-
| Remove | `DROP <TYPE> Module.Name` | `DROP ENTITY Shop.Product` |
36-
| List | `SHOW <TYPE>S [IN Module]` | `SHOW ENTITIES IN Shop` |
37-
| Inspect | `DESCRIBE <TYPE> Module.Name` | `DESCRIBE ENTITY Shop.Product` |
38-
| Security | `GRANT/REVOKE <perm> ON <target> TO/FROM <role>` | `GRANT READ ON Shop.Product TO Shop.User` |
33+
| Create | `create [MODIFIERS] <type> Module.Name (...)` | `create persistent entity Shop.Product (...)` |
34+
| Modify | `alter <type> Module.Name <operation>` | `alter entity Shop.Product add (...)` |
35+
| Remove | `drop <type> Module.Name` | `drop entity Shop.Product` |
36+
| List | `show <type>S [in module]` | `show entities in Shop` |
37+
| Inspect | `describe <type> Module.Name` | `describe entity Shop.Product` |
38+
| Security | `grant/revoke <perm> on <target> to/from <role>` | `grant read on Shop.Product to Shop.User` |
3939

40-
Do NOT use alternative verbs: `ADD` instead of `CREATE`, `REMOVE` instead of `DROP`, `LIST` instead of `SHOW`, `VIEW` instead of `DESCRIBE`.
40+
Do NOT use alternative verbs: `add` instead of `create`, `remove` instead of `drop`, `list` instead of `show`, `view` instead of `describe`.
4141

4242
### 3. Optimize for LLMs
4343

4444
- Keep patterns regular so one example is sufficient for generation
4545
- Statements must be self-contained (no implicit state from prior statements)
46-
- Use consistent keyword order: `<VERB> [MODIFIERS] <TYPE> <NAME> [CLAUSES] [BODY]`
46+
- Use consistent keyword order: `<VERB> [MODIFIERS] <type> <NAME> [CLAUSES] [body]`
4747
- Prefer flat statement sequences over deeply nested structures
4848

4949
### 4. Make Diffs Reviewable
5050

5151
- One property per line in multi-property constructs
5252
- Allow trailing commas
53-
- `DESCRIBE` output uses deterministic property order
53+
- `describe` output uses deterministic property order
5454
- Default values omitted unless non-obvious
5555

5656
### 5. Token Efficiency (Without Sacrificing Clarity)
5757

58-
- Omit noise words: `CREATE ENTITY` not `CREATE A NEW ENTITY`
59-
- Support `OR MODIFY` to avoid check-then-create
60-
- Allow type inference for obvious cases: `DECLARE $Count = 0`
58+
- Omit noise words: `create entity` not `create A NEW entity`
59+
- Support `or modify` to avoid check-then-create
60+
- Allow type inference for obvious cases: `declare $count = 0`
6161
- Do NOT use symbols to save tokens at the cost of readability
6262

6363
## Design Workflow
@@ -72,37 +72,37 @@ Does an existing pattern cover this? If yes, extend it. Don't invent new syntax.
7272

7373
```
7474
New feature: "image collections"
75-
Existing pattern: CREATE/ALTER/DROP/SHOW/DESCRIBE
76-
Design: CREATE IMAGE COLLECTION Module.Name (...)
77-
DESCRIBE IMAGE COLLECTION Module.Name
78-
SHOW IMAGE COLLECTIONS [IN Module]
75+
Existing pattern: create/alter/drop/show/describe
76+
design: create image collection Module.Name (...)
77+
describe image collection Module.Name
78+
show image COLLECTIONS [in module]
7979
```
8080

8181
### Step 2: Pick the Statement Shape
8282

8383
Every MDL statement fits one of these shapes:
8484

8585
```
86-
DDL: <VERB> [MODIFIERS] <TYPE> <QualifiedName> [CLAUSES] [BODY];
87-
DML: <ACTION> <TARGET> [CLAUSES];
88-
DQL: <QUERY-VERB> <TYPE>S [FILTERS];
86+
DDL: <VERB> [MODIFIERS] <type> <QualifiedName> [CLAUSES] [body];
87+
DML: <action> <TARGET> [CLAUSES];
88+
DQL: <query-VERB> <type>S [FILTERS];
8989
```
9090

9191
If your feature doesn't fit any shape, it may belong as a CLI command (`mxcli <subcommand>`) rather than MDL syntax.
9292

9393
### Step 3: Choose Keywords
9494

9595
1. Reuse existing keywords first (check reserved words in grammar)
96-
2. Use SQL/DDL verbs: `CREATE`, `ALTER`, `DROP`, `SHOW`, `DESCRIBE`, `GRANT`, `REVOKE`, `SET`
97-
3. Use Mendix terminology: `ENTITY` not `TABLE`, `MICROFLOW` not `FUNCTION`, `PAGE` not `VIEW`
98-
4. Prepositions clarify structure: `FROM`, `TO`, `IN`, `ON`, `BY`, `WITH`, `AS`, `WHERE`, `INTO`
96+
2. Use SQL/DDL verbs: `create`, `alter`, `drop`, `show`, `describe`, `grant`, `revoke`, `set`
97+
3. Use Mendix terminology: `entity` not `table`, `microflow` not `FUNCTION`, `page` not `view`
98+
4. Prepositions clarify structure: `from`, `to`, `in`, `on`, `by`, `with`, `as`, `where`, `into`
9999

100100
### Step 4: Write the Property List
101101

102102
All property-bearing constructs use this format:
103103

104104
```mdl
105-
CREATE <TYPE> Module.Name (
105+
create <type> Module.Name (
106106
Property1: value,
107107
Property2: value,
108108
);
@@ -115,29 +115,29 @@ Rules:
115115
- Trailing comma allowed
116116
- One property per line (single line acceptable for 1-2 properties)
117117

118-
#### Colon `:` vs `AS` — When to Use Each
118+
#### Colon `:` vs `as` — When to Use Each
119119

120120
Use **colon** for property definitions (assigning a value to a named property):
121121

122122
```mdl
123-
CREATE ENTITY Shop.Product (
124-
Name: String(200), -- property: type/value
125-
Price: Decimal,
123+
create entity Shop.Product (
124+
Name: string(200), -- property: type/value
125+
Price: decimal,
126126
);
127-
TEXTBOX txtName (Label: 'Name', Attribute: Title)
127+
textbox txtName (label: 'Name', attribute: title)
128128
```
129129

130-
Use **`AS`** for name-to-name mappings (renaming, aliasing, mapping one name to another):
130+
Use **`as`** for name-to-name mappings (renaming, aliasing, mapping one name to another):
131131

132132
```mdl
133-
CUSTOM NAME MAP (
134-
'kvkNummer' AS 'ChamberOfCommerceNumber', -- old name AS new name
135-
'naam' AS 'CompanyName',
133+
CUSTOM NAME map (
134+
'kvkNummer' as 'ChamberOfCommerceNumber', -- old name AS new name
135+
'naam' as 'CompanyName',
136136
)
137-
ALTER ENTITY Shop.Product RENAME Code AS ProductCode -- old attr AS new attr
137+
alter entity Shop.Product rename Code as ProductCode -- old attr AS new attr
138138
```
139139

140-
**Rule of thumb**: if the left side is a *fixed property key* defined by the syntax, use `:`. If the left side is a *user-provided name* being mapped to another name, use `AS`.
140+
**Rule of thumb**: if the left side is a *fixed property key* defined by the syntax, use `:`. If the left side is a *user-provided name* being mapped to another name, use `as`.
141141

142142
### Step 5: Validate
143143

@@ -147,31 +147,31 @@ Run these checks before finalizing syntax design:
147147
2. **LLM generation test** — Give one example to an LLM, ask for a variant. Does it get it right?
148148
3. **Diff test** — Change one property. Is the diff exactly one line?
149149
4. **Pattern test** — Does it follow CREATE/ALTER/DROP/SHOW/DESCRIBE? If not, why?
150-
5. **Roundtrip test** — Can `DESCRIBE` output be fed back as input?
150+
5. **Roundtrip test** — Can `describe` output be fed back as input?
151151

152152
## Anti-Patterns (DO NOT)
153153

154154
### Custom Verbs for Standard Operations
155155

156156
```mdl
157157
-- WRONG: custom verb
158-
SCHEDULE EVENT Shop.Cleanup ...
158+
SCHEDULE event Shop.Cleanup ...
159159
REGISTER WEBHOOK Shop.OnOrder ...
160160
161161
-- RIGHT: standard CREATE
162-
CREATE SCHEDULED EVENT Shop.Cleanup (...)
163-
CREATE WEBHOOK Shop.OnOrder (...)
162+
create SCHEDULED event Shop.Cleanup (...)
163+
create WEBHOOK Shop.OnOrder (...)
164164
```
165165

166166
### Implicit Module Context
167167

168168
```mdl
169169
-- WRONG: implicit state
170-
USE MODULE Shop;
171-
CREATE ENTITY Customer (...);
170+
use module Shop;
171+
create entity Customer (...);
172172
173173
-- RIGHT: explicit qualified name
174-
CREATE ENTITY Shop.Customer (...);
174+
create entity Shop.Customer (...);
175175
```
176176

177177
### Symbolic Syntax
@@ -181,19 +181,19 @@ CREATE ENTITY Shop.Customer (...);
181181
$items |> filter($.active) |> map($.name)
182182
183183
-- RIGHT: keyword-based
184-
FILTER $Items WHERE Active = true
184+
filter $Items where Active = true
185185
```
186186

187187
### Positional Arguments
188188

189189
```mdl
190190
-- WRONG: meaning unclear without docs
191-
CREATE RULE Shop Process Order ACT_ProcessOrder
191+
create rule Shop Process Order ACT_ProcessOrder
192192
193193
-- RIGHT: labeled properties
194-
CREATE RULE Shop.ProcessOrder (
195-
Type: Validation,
196-
Microflow: Shop.ACT_ProcessOrder,
194+
create rule Shop.ProcessOrder (
195+
type: validation,
196+
microflow: Shop.ACT_ProcessOrder,
197197
);
198198
```
199199

@@ -208,16 +208,16 @@ CREATE RULE Shop.ProcessOrder (
208208

209209
Before merging any PR that adds new MDL syntax, verify:
210210

211-
- [ ] Follows `CREATE`/`ALTER`/`DROP`/`SHOW`/`DESCRIBE` pattern
211+
- [ ] Follows `create`/`alter`/`drop`/`show`/`describe` pattern
212212
- [ ] Uses `Module.Element` qualified names (no bare names)
213-
- [ ] Property lists use `( Key: value, ... )` format
213+
- [ ] Property lists use `( key: value, ... )` format
214214
- [ ] Keywords are full English words (no abbreviations)
215215
- [ ] Statement reads as English (aloud test passed)
216216
- [ ] One example sufficient for LLM generation
217217
- [ ] Small change = one-line diff
218218
- [ ] No new keyword overloading
219219
- [ ] No implicit context dependency
220-
- [ ] `DESCRIBE` roundtrips to valid MDL
220+
- [ ] `describe` roundtrips to valid MDL
221221
- [ ] Grammar regenerated (`make grammar`)
222222
- [ ] Quick reference updated (`docs/01-project/MDL_QUICK_REFERENCE.md`)
223223
- [ ] Full-stack wired: grammar, AST, visitor, executor, DESCRIBE

0 commit comments

Comments
 (0)