fix(lint/check): #953 items 2-6 — BUTTON01 nested grids, native pages, return-only flows, CONV006 grouping, report --modules - #957
Merged
Conversation
…race (#951) SaveToFile now writes to a temp file in the cache's directory (VACUUM INTO, manual-copy fallback into the same temp file) and renames it over the cache. buildCatalog and refresh catalog communities no longer remove the cache first. Opening a cache at the current schema version no longer writes to it: a write on a file renamed underneath an open connection fails with SQLITE_READONLY_DBMOVED. File-backed connections get a busy_timeout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Starlark rule reading a struct field this mxcli does not expose is now reported at info level as "rule <ID> needs a newer mxcli (<detail>)"; other rule failures stay errors. Every rule failure is marked RuleFailure, kept out of BuildReport's score, summary and categories, and listed in its own "Rules That Could Not Run" section (ruleFailures in JSON). A configured rule severity no longer applies to the rule's own failure, and a rule file failing to load on an undefined name hints at a newer mxcli. Part of #952. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sync rules and CLAUDE.md (#952) - init and every sync write .ai-context/mxcli-tooling.json; any -p command warns once on stderr when the binary is provably older (releases by number, nightlies by tag date, mixed by build date, dev builds never). - init --sync-skills (alias --sync) refuses from an older binary instead of downgrading, and now also refreshes the bundled lint rules (by file name; user rules untouched) and the CLAUDE.md/AGENTS.md section between new mxcli:begin/end markers, keeping project notes outside them. - The bootstrap script compares the PATH binary and ./mxcli with the stamp before using them, downloads MXCLI_TAG instead of linking an older binary, and downloads through a temp file so a symlinked ./mxcli is never written through. Binaries <= v0.24.0 cannot read the stamp; the script is their guard. - init and new create mdlsource/ with a README. Closes #952. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docker check ran mx update-widgets on the user's project with only the MPRv2 storage snapshotted, so an MPRv1 .mpr was rewritten permanently, and mx check itself rewrote theme-cache/ and created deployment/sass/ on both formats, with or without --no-update-widgets. Both mx steps now run on a temporary copy (build output, caches and VCS folders skipped), mx output is rewritten to the project's own paths, and the output says that widgets were normalised on a copy and what that hides (#568, #646). docker build keeps its snapshot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto itself (#951) Check copies the project's directory, so a missing .mpr (or a path in /tmp) would copy an unrelated directory: fail early instead, and give the existing fake-mx tests a project file of their own. With TMPDIR inside the project the walk met its own copy and recursed until the path was too long; skip it. Trim the custom-widgets skill back under the 700-line limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A control-bar button of a data grid nested inside a data view or list view passing $currentObject was refused as CE1571, but there the control bar's $currentObject is the enclosing object and mxbuild 11.13 builds it clean. The walk now carries whether an ancestor data container supplies an object context; the grid's own data source still never scopes its control bar, so a top-level grid is still reported. Part of #953 (item 2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CE0582 is the React client's error. Measured on mxbuild 11.13.0: a
staticimage and a classic dropdown on a NativePhone_Default page build
clean, the same widgets on an Atlas_Default page are CE0582. A textbox
on an enumeration is CE2421 on both, so MDL-WIDGET39 is unchanged.
Nothing recorded a layout's platform: ListLayouts left Layout.Native
false for every layout, and LayoutType cannot tell the platforms apart.
- backend: Native is the content wrapper's type (NativeLayoutContent)
- catalog: layouts.Platform ("Web" / "Native"), schema 18
- linter: NativePages() joins pages.LayoutRef to layouts without the
Marketplace filter (the native layouts live in Atlas_Core); MPR012
skips those pages; Starlark layout.platform
- check: MDL-WIDGET40 skips a page whose layout resolves as native
Part of #953 (item 3).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A microflow or nanoflow whose only content is `return <expr>;` computes its value in the end event, which ActivityCount does not count. A non-Void return type is the witness that the end event returns a value, so those flows are no longer reported. Part of #953 (item 4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One finding per entity x role x CREATE/DELETE (111 on a mid-sized app) becomes one per entity, listing the de-duplicated roles per right. The test runs both the .claude and the embedded copy of the rule. Part of #953 (item 5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`lint` had -m, `report` only --exclude. `report --modules A,B` applies the same LintContext module filter and scores only the findings located in a selected module, so project-wide findings do not weigh on a module score. The selection is printed in markdown, HTML and JSON output. Part of #953 (item 6). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…MDL063 covers nanoflows Two calls to a void action carrying the same output name (Studio Pro names a JavaScript action's after the action, $RefreshEntity) are accepted by mxbuild 11.13.0, but check reported MDL063 (microflows) or 'already declared in this scope' (nanoflows), and describe called the model invalid. Measured: a void call's output name is inert - a later declare of the name builds clean, a use is CE0109. The return type is resolved from the script or, with -p, the project; an unresolvable action still counts. describe keeps printing the stored `$X =`: Studio Pro stores the name with UseReturnVariable=true, and the bare form would write an empty name. MDL063 now runs for nanoflows too (flow-wide, as measured in mxbuild): a duplicate output across if/else branches passed check and was CE0111. The check-time body validator no longer reports duplicate names for flows - it scoped them per branch and counted void calls; rules keep it. Part of #953 (item 1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… errors check --references accepted a Java action argument naming no parameter (CE1613 in mxbuild) whenever the script also had a semantic error: the reference tier was skipped, and a flow's body errors were returned instead of its reference errors. Both are now reported. call microflow / call nanoflow arguments are checked against the callee's parameters too (CE1613, measured on 11.13.0), and an action or flow known to take no parameters reports any named argument. Part of #953 (item 7). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…into c23-955 # Conflicts: # CHANGELOG.md
…to c23-958 # Conflicts: # CHANGELOG.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to c23-957 # Conflicts: # CHANGELOG.md # mdl/linter/report.go
A rule that could not run has no module; ScopeToModules dropped it, so a --modules report hid the failure that #952 lists separately. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #953 — items 2–6. Group d covers items 1 and 7, so this PR does not close the issue.
Changes (one commit per item)
2. MDL-BUTTON01 on a grid nested in a data container (
mdl/executor/validate_page_button_context.go)The tree walk now tracks whether an enclosing data container (a data view, list view, gallery or grid row) already supplies an object. A grid's own data source still does not scope its control bar, so a top-level grid is still reported.
3. MPR012 / MDL-WIDGET40 on native pages
ListLayoutssetsLayout.Native. It is true when the layout's content wrapper isForms$NativeLayoutContent. Before this, it was false for every layout.layouts.Platform(Web/Native), schema version 18. Documented in catalog-tables.md and catalog-schema.md, and exposed to Starlark aslayout.platform(write-lint-rules skill updated, value pinned in the vocabulary test).LintContext.NativePages()joinspages.LayoutReftolayouts. It does not apply the Marketplace filter, because the native layouts live in Atlas_Core. MPR012 skips those pages. Snippets are still reported (not measured).4. MPR002 on return-only flows (
mdl/linter/rules/empty.go): a flow with a non-VoidReturnTypeis not reported. Void and unset flows still are. No catalog change was needed.5. CONV006 grouped: one finding per entity, in the form
grants CREATE (M.Admin, M.User); DELETE (M.Admin). Roles are de-duplicated..claude/lint-rulesis synced to the embedded copy, and the test runs both copies.6.
report --modules/-m: applies the same LintContext filter aslint -m. The score counts only findings located in a selected module, so project-wide findings with no module are left out. The selection is printed in the markdown, HTML and JSON output. IfexcludeModulesin the config shadows a selected module, it is warned about, the same waylintdoes. Documented in docs-sitemxcli-report.md, the quick reference and the assess-quality skill.mxbuild measurements (11.13.0,
mxcli docker check, copy of the JTSBootLogboek app)btnOpen(grid inside a data view) is clean.btnOpen2(top-level grid) is CE1571.$currentObject: clean.Login_Native(NativePhone_Default) with a staticimage: clean.imgWithon Atlas_Default: CE0582.check --referenceson the probe script reports exactly those (WIDGET39 on both pages, WIDGET40 on the web page only).linton the app no longer reports MPR012 for imgNative or MPR002 for Logboek_Label / GetCurrentUser. CONV006 on Logboek with two roles gives one finding.Test plan
make build;go test ./mdl/executor/ ./mdl/linter/... ./mdl/catalog/ ./mdl/backend/modelsdk/ ./cmd/mxcli/make lint,make check-conformance,make check-findings,make check-mdl,make check-skill-mdl,make sync-skills,make sync-lint-rulesTestValidatePageButtonContext_NestedInDataContainerClean(data view + list view, top-level control)TestLayoutIsNative_ReadsTheContentWrapperTypeTestLayoutPlatformColumn_Issue953(catalog builder)TestLegacyImageWidgetRule_SkipsNativePages(web page as control)TestCheck_ClassicDropDownOnNativePageIsClean(web control, WIDGET39 still fires on native)TestEmptyMicroflowRule_SkipsReturnValueOnlyFlowsTestCONV006GroupsByEntityTestScopeToModulesreturnsValue: Logboek_Label / GetCurrentUser / IsValid reported againlayoutIsNative: "want native"ScopeToModules: unscoped findings keptFollow-ups (not done here)
tables.go).🤖 Generated with Claude Code