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
66 changes: 57 additions & 9 deletions cmd/mxcli/syntax/capability_docs_drift_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,29 @@ func readDoc(t *testing.T, name string) string {
// `mxcli syntax` topic is NOT sitting in the docs' "no MDL surface at all"
// table. The syntax registry is populated from the code, so it cannot claim a
// topic for something that does not exist.
// shippedCapabilities pairs a capability with the syntax topic that PROVES it
// ships. A topic is registered from Go code, so the pairing cannot go stale in
// the direction that matters: delete the feature and the topic goes with it.
//
// The last three were added after an audit found the matrix claiming all three
// were unavailable: "Microflow rules" and "Message definitions" sat under "Not
// Yet Implemented" (i.e. "no MDL surface at all") while both were authorable,
// and Layouts were described as "Read-only, no syntax topic" in three separate
// gap lists. None of it was caught, because this table did not name them — a
// hand-maintained guard only guards what someone remembered to add.
var shippedCapabilities = []struct{ topic, claim string }{
{"database-connection", "Ext. DB connector"},
{"queue", "Task queue"},
{"scheduled-event", "Scheduled events"},
{"regular-expression", "Regular expressions"},
{"image-collection", "Image collection"},
{"navigation.menu-document", "Menus"},
{"workflow", "Workflows"},
{"layout", "Layouts"},
{"microflow.rule", "Microflow rules"},
{"message-definition", "Message definitions"},
}

func TestCapabilityDocsDoNotClaimShippedFeaturesAreMissing(t *testing.T) {
matrix := readDoc(t, "MDL_FEATURE_MATRIX.md")

Expand All @@ -66,15 +89,7 @@ func TestCapabilityDocsDoNotClaimShippedFeaturesAreMissing(t *testing.T) {
// Each capability that must not appear as unimplemented, keyed by the syntax
// topic that proves it ships. A topic is registered from Go code, so this
// pairing cannot go stale in the direction that matters.
for _, c := range []struct{ topic, claim string }{
{"database-connection", "Ext. DB connector"},
{"queue", "Task queue"},
{"scheduled-event", "Scheduled events"},
{"regular-expression", "Regular expressions"},
{"image-collection", "Image collection"},
{"navigation.menu-document", "Menus"},
{"workflow", "Workflows"},
} {
for _, c := range shippedCapabilities {
if ByPath(c.topic) == nil {
t.Errorf("no `mxcli syntax %s` topic — either the feature was removed "+
"(then drop this row) or the topic is missing (then add it)", c.topic)
Expand Down Expand Up @@ -122,3 +137,36 @@ func TestMissingCapabilitiesIsMarkedAsDated(t *testing.T) {
}
}
}

// TestMissingSyntaxTopicsAreActuallyMissing closes the hole that let Layouts be
// listed as "Read-only, no syntax topic" while `mxcli syntax layout` answered.
//
// This is a direct contradiction rather than a judgement call, which is why it
// can be asserted mechanically: the section states a topic does not exist, and
// the registry says it does. Deliberately narrower than the Skills/Examples gap
// lists, where an entry can be true at the same time as a syntax topic exists —
// Regular Expressions has a topic AND genuinely has no skill.
func TestMissingSyntaxTopicsAreActuallyMissing(t *testing.T) {
matrix := readDoc(t, "MDL_FEATURE_MATRIX.md")

start := strings.Index(matrix, "### Missing Syntax Topics")
if start < 0 {
t.Fatal(`MDL_FEATURE_MATRIX.md has no "### Missing Syntax Topics" section — ` +
`if it was renamed, update this guard rather than deleting it`)
}
section := matrix[start:]
if end := strings.Index(section, "\n### "); end > 0 {
section = section[:end]
}

for _, c := range shippedCapabilities {
if ByPath(c.topic) == nil {
continue // covered by the sibling test, which reports it there
}
if strings.Contains(section, c.claim) {
t.Errorf("MDL_FEATURE_MATRIX.md lists %q under \"Missing Syntax Topics\", "+
"but `mxcli syntax %s` resolves — the doc tells a reader to look for "+
"syntax that is already published", c.claim, c.topic)
}
}
}
2 changes: 1 addition & 1 deletion docs-site/src/appendixes/quick-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ Cross-reference commands require `REFRESH CATALOG FULL` to populate reference da
| Stdin piping | `echo "CMD" \| mxcli -p app.mpr` | Quiet mode, pipe-friendly |
| Check syntax | `mxcli check script.mdl` | Parse-only validation |
| Check references | `mxcli check script.mdl -p app.mpr --references` | With reference validation |
| Lint project | `mxcli lint -p app.mpr [--format json\|sarif]` | 14 built-in + 27 Starlark rules |
| Lint project | `mxcli lint -p app.mpr [--format json\|sarif]` | 19 built-in + 31 Starlark rules |
| Report | `mxcli report -p app.mpr [--format markdown\|json\|html]` | Best practices report |
| Test | `mxcli test tests/ -p app.mpr` | `.test.mdl` / `.test.md` files |
| Diff script | `mxcli diff -p app.mpr changes.mdl` | Compare script vs project |
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/migration/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mxcli check script.mdl
# 2. Reference validation (checks entity/microflow names exist)
mxcli check script.mdl -p app.mpr --references

# 3. Lint the full project (41 built-in + 27 Starlark rules)
# 3. Lint the full project (19 built-in + 31 Starlark rules)
mxcli lint -p app.mpr

# 4. Quality report (scored 0-100 per category)
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/reference/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ Everything mxcli can do, organized by use case.
| Cross-references | `LIST CALLERS/CALLEES OF` | Who calls what |
| Impact analysis | `LIST IMPACT OF Module.Entity` | What breaks if I change this |
| Transitive callers | `LIST CALLERS OF ... TRANSITIVE` | Full call chain |
| Linting | `mxcli lint -p app.mpr` | 14 built-in + 27 Starlark rules |
| Linting | `mxcli lint -p app.mpr` | 19 built-in + 31 Starlark rules |
| Best practices report | `mxcli report -p app.mpr` | Scored report with categories |
| Missing translations | QUAL005 linter rule | Detects incomplete translations |
| Catalog queries | `SELECT ... FROM CATALOG.tables` | SQL over project metadata |
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/tutorial/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ For a broader set of checks across the entire project (not just a single script)
mxcli lint -p app.mpr
```

This runs 14 built-in rules plus 29 Starlark rules covering security, architecture, quality, and naming conventions. See `mxcli lint --list-rules` for the full list.
This runs 19 built-in rules plus 31 Starlark rules covering security, architecture, quality, and naming conventions. See `mxcli lint --list-rules` for the full list.

For CI/CD integration, output in SARIF format:

Expand Down
45 changes: 21 additions & 24 deletions docs/01-project/MDL_FEATURE_MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,11 @@ live distinction is **MPR vs MCP**.
| **Associations** | Y | Y | Y | N | Y | Y | 01 | Y | N | Y | Y | Y | Y | Y | Y | Y | N |
| **Enumerations** | Y | Y | Y | Y | Y | Y | 01 | Y | Y | N | Y | Y | Y | N | Y | Y | Y |
| **Microflows** | Y | Y | Y | Y | Y | N | 02 | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
| **Nanoflows** | Y | Y | Y | Y | Y | N | Y | Y | Y | Y | Y | Y | Y | Y | P | N | N |
| **Nanoflows** | Y | Y | Y | Y | Y | N | 02b | Y | Y | Y | Y | Y | Y | Y | P | N | N |
| **Rules** | Y | Y | Y | Y | Y | N | Y | Y | Y | Y | N | Y | Y | N | N | Y | N |
| **Pages** | Y | Y | Y | N | Y | Y | 03 | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y |
| **Snippets** | Y | Y | Y | N | Y | Y | 03 | Y | Y | Y | Y | Y | Y | N | Y | Y | Y |
| **Layouts** | Y | Y | N | N | N | N | N | N | Y | Y | Y | N | Y | N | Y | N | N |
| **Layouts** | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | Y | N | Y | Y | N |
| **Java Actions** | Y | Y | Y | N | Y | N | 07 | Y | Y | Y | Y | Y | Y | N | Y | Y | N |
| **Constants** | Y | Y | Y | Y | Y | N | 09 | Y | N | P | Y | N | Y | N | P | N | N |
| **OData Clients** | Y | Y | Y | Y | Y | Y | 10 | Y | Y | P | Y | Y | Y | N | Y | Y | N |
Expand All @@ -178,24 +179,25 @@ live distinction is **MPR vs MCP**.
| **Modules** | Y | Y | Y | N | Y | N | all | Y | Y | Y | Y | Y | Y | N | Y | N | N |
| **Navigation** | Y | Y | Y | - | - | Y | 11 | N | Y | Y | Y | Y | Y | N | N | Y | N |
| **Business Events** | Y | Y | Y | N | Y | N | 13 | N | Y | N | Y | N | Y | N | Y | Y | N |
| **Project Settings** | Y | Y | - | - | - | Y | N | N | Y | Y | Y | N | Y | N | N | Y | P |
| **Task Queues** | Y | Y | Y | Y | Y | N | 21 | Y | Y | N | N | Y | Y | N | Y | Y | N |
| **Scheduled Events** | Y | Y | Y | Y | Y | N | 21 | Y | Y | Y | N | Y | Y | N | Y | Y | N |
| **Project Settings** | Y | Y | - | - | - | Y | 14 | N | Y | Y | Y | N | Y | N | N | Y | P |
| **Task Queues** | Y | Y | Y | Y | Y | N | Y | Y | Y | N | N | Y | Y | N | Y | Y | N |
| **Scheduled Events** | Y | Y | Y | Y | Y | N | Y | Y | Y | Y | N | Y | Y | N | Y | Y | N |
| **Database Connections** | Y | Y | Y | Y | Y | N | 05 | Y | Y | N | N | Y | Y | N | Y | Y | N |
| **Regular Expressions** | Y | Y | Y | Y | Y | N | N | Y | Y | Y | N | N | Y | N | Y | Y | N |
| **Validation Rules** | - | Y | Y | - | - | Y | N | Y | N | Y | N | N | Y | N | N | Y | N |
| **Menus** | - | Y | Y | Y | Y | N | N | Y | N | N | N | N | Y | N | N | Y | N |
| **Image Collections** | Y | Y | Y | N | Y | N | N | Y | N | N | N | N | Y | N | Y | Y | N |
| **JavaScript Actions** | Y | Y | Y | N | Y | N | N | Y | Y | Y | N | N | Y | N | Y | N | N |
| **Published REST Services** | Y | Y | Y | Y | Y | N | N | N | Y | N | P | N | Y | N | N | Y | N |
| **Regular Expressions** | Y | Y | Y | Y | Y | N | Y | Y | Y | Y | N | N | Y | N | Y | Y | N |
| **Validation Rules** | - | Y | Y | - | - | Y | Y | Y | N | Y | N | N | Y | N | N | Y | N |
| **Menus** | - | Y | Y | Y | Y | N | 26 | Y | N | N | N | N | Y | N | N | Y | N |
| **Image Collections** | Y | Y | Y | N | Y | N | 19 | Y | N | N | N | N | Y | N | Y | Y | N |
| **JavaScript Actions** | Y | Y | Y | N | Y | N | 07b | Y | Y | Y | N | N | Y | N | Y | N | N |
| **Published REST Services** | Y | Y | Y | Y | Y | N | 22 | N | Y | N | P | N | Y | N | N | Y | N |
| **REST Clients** | Y | Y | Y | Y | Y | Y | 06 | Y | Y | P | Y | Y | Y | N | Y | Y | N |
| **Import Mappings** | Y | Y | Y | N | Y | N | 06 | Y | N | N | P | Y | N | N | N | Y | N |
| **Export Mappings** | Y | Y | Y | N | Y | N | 06 | Y | N | N | P | Y | N | N | N | Y | N |
| **Import Mappings** | Y | Y | Y | N | Y | N | 21 | Y | N | N | P | Y | N | N | N | Y | N |
| **Export Mappings** | Y | Y | Y | N | Y | N | 21 | Y | N | N | P | Y | N | N | N | Y | N |
| **JSON Structures** | Y | Y | Y | Y | Y | N | 20 | Y | N | N | P | N | N | N | N | N | N |
| **Workflows** | Y | Y | Y | N | Y | Y | N | Y | Y | Y | N | Y | Y | N | N | Y | N |
| **AI Agent documents** | Y | Y | Y | N | Y | N | N | Y | N | N | N | Y | Y | N | Y | Y | N |
| **Pluggable widgets** | Y | Y | Y | - | Y | Y | 03 | Y | N | N | P | Y | Y | N | N | Y | N |
| **Data Transformers** | Y | Y | Y | N | Y | N | N | Y | N | N | N | N | Y | N | Y | Y | N |
| **Message Definitions** | Y | Y | Y | Y | Y | Y | 40 | Y | N | N | N | N | Y | N | N | Y | N |
| **Workflows** | Y | Y | Y | N | Y | Y | 24 | Y | Y | Y | N | Y | Y | N | N | Y | N |
| **AI Agent documents** | Y | Y | Y | N | Y | N | 27 | Y | N | N | N | Y | Y | N | Y | Y | N |
| **Pluggable widgets** | Y | Y | Y | - | Y | Y | 30 | Y | N | N | P | Y | Y | N | N | Y | N |
| **Data Transformers** | Y | Y | Y | N | Y | N | 23 | Y | N | N | N | N | Y | N | Y | Y | N |

## Security Features

Expand All @@ -214,7 +216,7 @@ live distinction is **MPR vs MCP**.

| Feature | SHOW | DESCRIBE | CREATE | OR MODIFY | DROP | ALTER | Examples | Tests | Catalog | REFS | LSP | Skills | Help | Viz | REPL | Syntax | Starlark |
|---------|------|----------|--------|-----------|------|-------|----------|-------|---------|------|-----|--------|------|-----|------|--------|----------|
| **Folders** | N | N | P | N | N | N | N | P | N | N | P | Y | Y | - | N | N | N |
| **Folders** | N | N | P | N | N | N | 18 | P | N | N | P | Y | Y | - | N | N | N |
| **MOVE** | - | - | - | - | - | - | N | P | N | N | P | Y | Y | - | N | Y | N |

## External SQL & Data
Expand All @@ -236,7 +238,7 @@ live distinction is **MPR vs MCP**.
| **Catalog Query** | `select ... from CATALOG.<table>` | Y | Y | SQL against project metadata |
| **Cross-References** | `show callers/callees/references/impact/context of` | Y | Y | Requires `refresh catalog full` |
| **Full-Text Search** | `search '<keyword>'` | Y | Y | Across all strings and source |
| **Linting** | `mxcli lint -p app.mpr` | Y | Y | 14 built-in + 27 Starlark rules |
| **Linting** | `mxcli lint -p app.mpr` | Y | Y | 19 built-in + 31 Starlark rules |
| **Report** | `mxcli report -p app.mpr` | Y | Y | Scored best practices report |
| **Widget Discovery** | `show widgets [in module] [where ...]` | Y | Y | Experimental |
| **Widget Update** | `update widgets set ... where ...` | Y | Y | Bulk pluggable widget updates |
Expand Down Expand Up @@ -294,7 +296,6 @@ These types are not covered in `help.go` output:

### Missing Skills

- **Layouts** — Read-only, no skill needed
- **Constants** — No dedicated skill

### Missing Tests
Expand All @@ -303,7 +304,6 @@ These types are not covered in `help.go` output:

### Missing Examples

- **Layouts** — Read-only, no example needed
- **Folders / MOVE** — No dedicated example file

### Missing REPL Autocomplete
Expand All @@ -318,7 +318,6 @@ These types are not covered in `help.go` output:

- **Constants** — No `mxcli syntax constant` topic
- **Nanoflows** — No dedicated syntax topic (covered by microflow topic)
- **Layouts** — Read-only, no syntax topic
- **Modules** — No dedicated syntax topic

### Missing Starlark APIs
Expand Down Expand Up @@ -368,8 +367,6 @@ Document types that exist in Mendix and have **no** MDL surface at all.

| Feature | Notes |
|---------|-------|
| **Microflow rules** (`Microflows$Rule`) | Reusable decision logic called from a microflow. Not to be confused with `CREATE VALIDATION RULE`, which is an attribute constraint and *is* supported |
| **Message definitions** (`MessageDefinitions$MessageDefinitionCollection`) | Message definition documents |
| **XML schemas** | Imported XSD documents |
| **Web service publish / consume** | SOAP. `CALL WEB SERVICE` exists in microflows for a stored service; the service documents themselves are not authorable |
| **Data importer** | Excel/CSV import documents |
Expand Down
2 changes: 1 addition & 1 deletion docs/01-project/MDL_QUICK_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1867,7 +1867,7 @@ Name the widget the way you write it in a page body. The target is stored as the
| Execute script | `mxcli exec script.mdl -p app.mpr` | Script file |
| Check syntax | `mxcli check script.mdl` | Parse-only validation |
| Check references | `mxcli check script.mdl -p app.mpr --references` | With reference validation |
| Lint project | `mxcli lint -p app.mpr [--format json\|sarif]` | 15 built-in + 27 Starlark rules |
| Lint project | `mxcli lint -p app.mpr [--format json\|sarif]` | 19 built-in + 31 Starlark rules |
| Report | `mxcli report -p app.mpr [--format markdown\|json\|html]` | Best practices report |
| Test | `mxcli test tests/ -p app.mpr` | `.test.mdl` / `.test.md` files |
| Diff script | `mxcli diff -p app.mpr changes.mdl` | Compare script vs project |
Expand Down
Loading