Skip to content

fix(lint/check): #953 items 2-6 — BUTTON01 nested grids, native pages, return-only flows, CONV006 grouping, report --modules - #957

Merged
ako merged 17 commits into
mainfrom
fix/953-lint-false-positives
Oct 3, 2026
Merged

ako merged 17 commits into
mainfrom
fix/953-lint-false-positives

Conversation

@ako

@ako ako commented Oct 3, 2026

Copy link
Copy Markdown
Owner

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

  • backend ListLayouts sets Layout.Native. It is true when the layout's content wrapper is Forms$NativeLayoutContent. Before this, it was false for every layout.
  • catalog: layouts.Platform (Web / Native), schema version 18. Documented in catalog-tables.md and catalog-schema.md, and exposed to Starlark as layout.platform (write-lint-rules skill updated, value pinned in the vocabulary test).
  • linter: LintContext.NativePages() joins pages.LayoutRef to layouts. 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).
  • check: MDL-WIDGET40 (classic dropdown, CE0582) skips a page whose layout resolves as native. MDL-WIDGET39 (CE2421) stays as it is, because mxbuild still reports CE2421 on a native page (measured).

4. MPR002 on return-only flows (mdl/linter/rules/empty.go): a flow with a non-Void ReturnType is 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-rules is synced to the embedded copy, and the test runs both copies.

6. report --modules/-m: applies the same LintContext filter as lint -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. If excludeModules in the config shadows a selected module, it is warned about, the same way lint does. Documented in docs-site mxcli-report.md, the quick reference and the assess-quality skill.

mxbuild measurements (11.13.0, mxcli docker check, copy of the JTSBootLogboek app)

  • Page Logboek_Images: btnOpen (grid inside a data view) is clean. btnOpen2 (top-level grid) is CE1571.
  • Probe page with a grid inside a list view, control-bar button passing $currentObject: clean.
  • Login_Native (NativePhone_Default) with a staticimage: clean. imgWith on Atlas_Default: CE0582.
  • Native_Probe: dropdown on an enum is clean, a textbox on an enum is CE2421. Web_Probe: dropdown CE0582, textbox CE2421.
  • After the fix, check --references on the probe script reports exactly those (WIDGET39 on both pages, WIDGET40 on the web page only). lint on 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-rules
  • New tests, each written first and seen failing with the reported symptom:
    • TestValidatePageButtonContext_NestedInDataContainerClean (data view + list view, top-level control)
    • TestLayoutIsNative_ReadsTheContentWrapperType
    • TestLayoutPlatformColumn_Issue953 (catalog builder)
    • TestLegacyImageWidgetRule_SkipsNativePages (web page as control)
    • TestCheck_ClassicDropDownOnNativePageIsClean (web control, WIDGET39 still fires on native)
    • TestEmptyMicroflowRule_SkipsReturnValueOnlyFlows
    • TestCONV006GroupsByEntity
    • TestScopeToModules
  • Revert checks: removed each fix in turn and confirmed its test fails with the original symptom:
    • BUTTON01 context flag: btnOpen flagged again
    • MPR012 native skip: Login_Native reported again
    • WIDGET40 native skip: MDL-WIDGET40 on the native page
    • MPR002 returnsValue: Logboek_Label / GetCurrentUser / IsValid reported again
    • layoutIsNative: "want native"
    • ScopeToModules: unscoped findings kept
    • CONV006: 4 violations before the rewrite

Follow-ups (not done here)

  • A snippet with a legacy image is still reported by MPR012. A snippet records no layout, and whether a native snippet builds clean has not been measured.
  • MPR010 ("wrap the data view in a layoutgrid") also fires on native pages, which have no layout grid widget. It has the same web-only premise and needs its own measurement.
  • The MDL-WIDGET39 message lists AutoNumber among the accepted types. On a native page mxbuild's CE2421 text omits it. The finding is correct; only the wording is off.
  • A layout created in the same script is not resolved as native by MDL-WIDGET40, so the check stays as loud as before for it.
  • Catalog schema bumped to 18. If a parallel branch also bumps, the merge needs one more bump (see the history note in tables.go).

🤖 Generated with Claude Code

ako and others added 17 commits October 3, 2026 14:39
…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>
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant