From b70e1084d599dd2e5d041cc2b7ac86f54dd6f7f7 Mon Sep 17 00:00:00 2001 From: Ako Date: Fri, 25 Sep 2026 12:48:18 +0000 Subject: [PATCH] docs(matrix): audit the feature matrix against what actually ships The matrix claimed two shipped document types were unavailable, which is the failure its own "Keeping this honest" note warns about -- a row claiming a gap that has since been filled sends people to Studio Pro for work mxcli can do. - Microflow rules sat under "Not Yet Implemented" ("no MDL surface at all") while CREATE [OR MODIFY] RULE ships with a skill, rules.mdl, a `microflow.rule` syntax topic, a CATALOG.RULES view and rule REFS edges. - Message definitions likewise: SHOW / DESCRIBE / CREATE OR MODIFY / DROP / ALTER all ship, with tests and examples. Both now have rows in Core Document Types instead. Layouts were recorded as read-only in four places -- the row's CREATE, OR MODIFY, DROP, ALTER, Examples, Tests, Skills and Syntax cells were all N, and three gap lists repeated "Read-only". All eight are Y. OR MODIFY was verified at exec rather than parse: `create or replace` reports Created then Unchanged, and `create or modify` over the stored layout reports Unchanged. Sixteen Examples cells corrected against the doctype-tests listing, including two that cited the wrong file -- Task Queues and Scheduled Events both pointed at 21 (import/export mappings) and the mapping rows pointed at 06 (the REST client). Rule counts are measured, not remembered: 19 built-in (`lint --list-rules` with no project rules dir) and 31 Starlark (`.claude/lint-rules/*.star`). Four different wrong pairs were in circulation across five live docs, one claiming 41 built-in rules. CHANGELOG and the dated eval proposal are left alone: they are records of a past state, not claims about the present. The guard could not have caught any of it. TestCapabilityDocsDoNotClaim... reads only the "Not Yet Implemented" section and checks a hand-maintained list of seven capabilities naming neither rules, message definitions nor layouts. So the list is hoisted to `shippedCapabilities`, extended with all three, and a second test asserts that "Missing Syntax Topics" may not list a capability whose `mxcli syntax` topic resolves -- a flat contradiction, which is what makes it mechanically assertable. It is deliberately not extended to the Skills and Examples gap lists, where an entry can be true at the same time as a syntax topic exists (Regular Expressions has a topic and no skill). Checked by reinstating all three false claims: two tests fail, naming each. Co-Authored-By: Claude Opus 5 (1M context) --- .../syntax/capability_docs_drift_test.go | 66 ++++++++++++++++--- docs-site/src/appendixes/quick-reference.md | 2 +- docs-site/src/migration/validation.md | 2 +- docs-site/src/reference/capabilities.md | 2 +- docs-site/src/tutorial/validation.md | 2 +- docs/01-project/MDL_FEATURE_MATRIX.md | 45 ++++++------- docs/01-project/MDL_QUICK_REFERENCE.md | 2 +- 7 files changed, 83 insertions(+), 38 deletions(-) diff --git a/cmd/mxcli/syntax/capability_docs_drift_test.go b/cmd/mxcli/syntax/capability_docs_drift_test.go index 2c78ffe9dd..c1950bd90a 100644 --- a/cmd/mxcli/syntax/capability_docs_drift_test.go +++ b/cmd/mxcli/syntax/capability_docs_drift_test.go @@ -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") @@ -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) @@ -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) + } + } +} diff --git a/docs-site/src/appendixes/quick-reference.md b/docs-site/src/appendixes/quick-reference.md index 24e4914f8f..a11276dad4 100644 --- a/docs-site/src/appendixes/quick-reference.md +++ b/docs-site/src/appendixes/quick-reference.md @@ -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 | diff --git a/docs-site/src/migration/validation.md b/docs-site/src/migration/validation.md index 2df058ccfe..0c173d2ac8 100644 --- a/docs-site/src/migration/validation.md +++ b/docs-site/src/migration/validation.md @@ -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) diff --git a/docs-site/src/reference/capabilities.md b/docs-site/src/reference/capabilities.md index 5bf56c2307..f8a8bef35b 100644 --- a/docs-site/src/reference/capabilities.md +++ b/docs-site/src/reference/capabilities.md @@ -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 | diff --git a/docs-site/src/tutorial/validation.md b/docs-site/src/tutorial/validation.md index 3003709d22..c668447f67 100644 --- a/docs-site/src/tutorial/validation.md +++ b/docs-site/src/tutorial/validation.md @@ -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: diff --git a/docs/01-project/MDL_FEATURE_MATRIX.md b/docs/01-project/MDL_FEATURE_MATRIX.md index e1e3bc5f3e..9d2c96df67 100644 --- a/docs/01-project/MDL_FEATURE_MATRIX.md +++ b/docs/01-project/MDL_FEATURE_MATRIX.md @@ -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 | @@ -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 @@ -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 @@ -236,7 +238,7 @@ live distinction is **MPR vs MCP**. | **Catalog Query** | `select ... from CATALOG.` | 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 ''` | 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 | @@ -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 @@ -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 @@ -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 @@ -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 | diff --git a/docs/01-project/MDL_QUICK_REFERENCE.md b/docs/01-project/MDL_QUICK_REFERENCE.md index 67ca255ca7..b9606b4dcf 100644 --- a/docs/01-project/MDL_QUICK_REFERENCE.md +++ b/docs/01-project/MDL_QUICK_REFERENCE.md @@ -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 |