Skip to content

Commit 4c7649c

Browse files
authored
Merge branch 'main' into feature/213-catalog-search
2 parents 3a81bbb + 8cd529f commit 4c7649c

597 files changed

Lines changed: 78114 additions & 54340 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.
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# /mxcli-dev:proposal — Create Feature Proposal
2+
3+
Guide the contributor through creating a well-structured feature proposal for
4+
mxcli. The proposal goes in `docs/11-proposals/PROPOSAL_<name>.md`.
5+
6+
## Process
7+
8+
Work through these phases **interactively** — ask the user questions, don't
9+
guess. Each phase produces concrete output.
10+
11+
### Phase 1: Understand the Feature
12+
13+
Ask the user:
14+
15+
1. **What** do you want to add? (one sentence)
16+
2. **Why** — what problem does this solve, or what user story does it enable?
17+
3. **Which Mendix version** introduced this capability? (affects version-gating)
18+
4. **Does this add MDL syntax?** (CREATE/ALTER/DROP/SHOW/DESCRIBE statements)
19+
5. **Does this touch BSON serialization?** (reading or writing Mendix documents)
20+
21+
If the user isn't sure about version or BSON, help them find out:
22+
- Version: check `reference/mendixmodellib/reflection-data/` or Mendix release notes
23+
- BSON: check if similar features exist in `sdk/mpr/parser*.go` or `sdk/mpr/writer*.go`
24+
25+
### Phase 2: BSON Investigation (if applicable)
26+
27+
**CRITICAL**: If the feature reads or writes Mendix documents, investigate the
28+
BSON structure BEFORE designing syntax. Wrong assumptions here cause CE errors
29+
in Studio Pro that are painful to debug.
30+
31+
1. **Find a working example** — ask the user:
32+
- "Do you have a test `.mpr` project with this feature already configured in Studio Pro?"
33+
- If yes: use `mxcli bson dump` or `mxcli bson discover` to extract the BSON structure
34+
- If no: ask them to create a minimal example in Studio Pro first
35+
36+
2. **Extract the BSON structure**:
37+
```bash
38+
# Find the document type
39+
./bin/mxcli -p project.mpr -c "SHOW STRUCTURE ALL" | grep -i <feature-name>
40+
41+
# Dump the raw BSON
42+
./bin/mxcli bson dump -p project.mpr --type "<BSON $Type>"
43+
44+
# Or discover all instances of a type
45+
./bin/mxcli bson discover -p project.mpr --pattern "<pattern>"
46+
```
47+
48+
3. **Document the BSON structure** in the proposal:
49+
- Storage name (`$Type` field) — verify against `reference/mendixmodellib/reflection-data/`
50+
- All fields with types and observed values
51+
- Any fields that use Mendix-internal IDs (pointers to other documents)
52+
- Note any counter-intuitive naming (like Parent/Child pointer inversion)
53+
54+
4. **Check for storage-name vs qualified-name mismatches** — consult the table
55+
in CLAUDE.md under "BSON Storage Names vs Qualified Names". If the feature
56+
uses a type that has a known mismatch, document it prominently.
57+
58+
### Phase 3: Check for Overlap
59+
60+
Before writing the proposal, search for existing work:
61+
62+
```bash
63+
# Existing proposals
64+
ls docs/11-proposals/ | grep -i <feature>
65+
66+
# Existing implementations
67+
grep -r "<feature>" mdl/executor/ sdk/mpr/ --include="*.go" -l
68+
69+
# Existing test coverage
70+
ls mdl-examples/doctype-tests/ | grep -i <feature>
71+
```
72+
73+
If there's overlap, discuss with the user whether to extend the existing work
74+
or start fresh.
75+
76+
### Phase 4: Design MDL Syntax (if applicable)
77+
78+
If the feature adds MDL statements, read `.claude/skills/design-mdl-syntax.md`
79+
first, then design syntax that follows these principles:
80+
81+
- Uses standard verbs: `CREATE`, `ALTER`, `DROP`, `SHOW`, `DESCRIBE`
82+
- Reads as English — a business analyst understands it
83+
- Uses `Module.Element` qualified names everywhere
84+
- Property format: `( Key: value, ... )` with colon separators
85+
- One example is enough for an LLM to generate correct variants
86+
- Adding one property is a one-line diff
87+
88+
Present the proposed syntax to the user and ask for feedback before proceeding.
89+
90+
### Phase 5: Write the Proposal
91+
92+
Create `docs/11-proposals/PROPOSAL_<snake_case_name>.md` with this structure:
93+
94+
```markdown
95+
# Proposal: <Title>
96+
97+
**Status:** Draft
98+
**Date:** <today's date>
99+
100+
## Problem Statement
101+
102+
<What problem does this solve? Who benefits?>
103+
104+
## BSON Structure
105+
106+
<Document the storage format. Include the $Type, all fields, pointer
107+
relationships, and any gotchas. If not applicable, explain why.>
108+
109+
## Proposed MDL Syntax
110+
111+
<Show CREATE/ALTER/DROP/SHOW/DESCRIBE examples. If not MDL syntax,
112+
describe the CLI commands or API changes.>
113+
114+
## Implementation Plan
115+
116+
<Which files need to change? What's the order of operations?>
117+
118+
### Files to modify/create
119+
120+
| File | Change |
121+
|------|--------|
122+
| `mdl/grammar/MDLParser.g4` | Add rule for ... |
123+
| `mdl/ast/...` | New AST node |
124+
| ... | ... |
125+
126+
## Version Compatibility
127+
128+
<Which Mendix version introduced this? Does it need version-gating?>
129+
130+
## Test Plan
131+
132+
<What test scripts go in mdl-examples/doctype-tests/? What roundtrip
133+
tests are needed?>
134+
135+
## Open Questions
136+
137+
<What's unresolved? What needs user input or further investigation?>
138+
```
139+
140+
### Phase 6: Confirm with User
141+
142+
Show the user the proposal and ask:
143+
- "Does this look right?"
144+
- "Anything I should add or change?"
145+
- "Ready to commit?"
146+
147+
If confirmed, commit the proposal file.
148+
149+
---
150+
151+
## Important Reminders
152+
153+
- **Never guess BSON field names.** Always verify against a real `.mpr` file or
154+
the reflection data. Wrong field names cause silent data corruption.
155+
- **Don't skip the BSON investigation** for features that touch Mendix documents.
156+
The proposal will be wrong without it, and the implementation will produce
157+
CE errors in Studio Pro.
158+
- **Check existing proposals first.** The `docs/11-proposals/` directory has 30+
159+
proposals — some may cover the same ground or provide useful reference.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# /mxcli-dev:review — PR Review
2+
3+
Run a structured review of the current branch's changes against the CLAUDE.md
4+
checklist, then check the recurring findings table below for patterns that have
5+
burned us before.
6+
7+
## Steps
8+
9+
1. Run `gh pr view` and `gh pr diff` (or `git diff main...HEAD`) to read the change.
10+
2. Work through the CLAUDE.md "PR / Commit Review Checklist" in full.
11+
3. Then check every row in the Recurring Findings table below — flag any match.
12+
4. Report: blockers first, then moderate issues, then minor. Include a concrete fix
13+
option for every blocker (not just "this is wrong").
14+
5. After the review: **add a row** to the Recurring Findings table for any new
15+
pattern not already covered.
16+
17+
---
18+
19+
## Recurring Findings
20+
21+
Patterns caught in real reviews. Each row is a class of mistake worth checking
22+
proactively. Add a row after every review that surfaces something new.
23+
24+
| # | Finding | Category | Canonical fix |
25+
|---|---------|----------|---------------|
26+
| 1 | Formatter emits a keyword not present in `MDLParser.g4` → DESCRIBE output won't re-parse (e.g. `RANGE(...)`) | DESCRIBE roundtrip | Grep grammar before assuming a keyword is valid; if construct can't be expressed yet, emit `-- TypeName(field=value) — not yet expressible in MDL` |
27+
| 2 | Output uses `$currentObject/Attr` prefix — non-idiomatic; Studio Pro uses bare attribute names | Idiomatic output | Verify against a real Studio Pro BSON sample before choosing a prefix convention |
28+
| 3 | Malformed BSON field (missing key, wrong type) produces silent garbage output (e.g. `RANGE($x, , )`) | Error handling | Default missing numeric fields to `"0"`; or emit `-- malformed <TypeName>` rather than broken MDL |
29+
| 4 | No DESCRIBE roundtrip test — grammar gap went undetected until human review | Test coverage | Add roundtrip test: format struct → MDL string → parse → confirm no error |
30+
| 5 | Hardcoded personal path in committed file (e.g. `/c/Users/Ylber.Sadiku/...`) | Docs quality | Use bare commands (`go test ./...`) without absolute paths in any committed doc or skill |
31+
| 6 | Docs-only PR cites an unmerged PR as a "model example" — cited PR had blockers | Docs quality | Only cite merged, verified PRs; or annotate with known gaps if citing in-flight work |
32+
| 7 | Skill/doc table references a function that doesn't exist (e.g. `formatActionStatement()` vs `formatAction()`) | Docs quality | Grep function names before writing: `grep -r "func formatA" mdl/executor/` |
33+
| 8 | "Always X" rule is too absolute for trivial edge cases (e.g. "always write failing test first" for one-char typos) | Docs quality | Soften to "prefer X" or add an exception clause; include the reasoning so readers can judge edge cases |
34+
| 9 | Doc comment promises a fallback/feature that doesn't exist in the code (e.g., "raw-map fallback in the client" when no such fallback was implemented) | Docs quality | Grep for function/type names referenced in doc comments to confirm they exist before committing |
35+
36+
---
37+
38+
## After Every Review
39+
40+
- [ ] All blockers have a concrete fix option stated.
41+
- [ ] Recurring Findings table updated with any new pattern.
42+
- [ ] If docs-only PR: every function name, path, and PR reference verified against
43+
live code before approving.

.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

0 commit comments

Comments
 (0)