Skip to content

Sync ako/mxcli: layout-grid appearance round-trip, bare page-variable defaults, MPR007 home pages - #1372

Merged
ako merged 16 commits into
mendixlabs:mainfrom
ako:main
Oct 10, 2026
Merged

ako merged 16 commits into
mendixlabs:mainfrom
ako:main

Conversation

@ako

@ako ako commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

Syncs ako/mxcli:main into mendixlabs/mxcli:main: 13 commits since #1371, landed in the fork through PRs ako#1083, ako#1085 and ako#1086.

Pages

  • Layout-grid row/column appearance and alignment survive describe → exec. A round trip of a Studio Pro page lost every design property, class and style on its rows and columns (46 → 33 design property values on one home page) and reset vertical alignment, while check, exec and mx check were all green. The parser, builder and writer now all carry them, and two snippets leave the roundtrip known-failures list.
  • A page variable's default is written as a bare expression: $show: Boolean = true, = if (…) then … else …, = Module.Enum.Value. The quoted string form keeps its meaning under mdl 1; and is the deprecated alias MDL-DEPR086, refused from mdl 2 with a fmt --upgrade rewrite.
  • No false MDL-WIDGET07 for pluggablewidget '<id>' properties when check runs without a project.

Messages and hints

  • GRANT echoes the rule it wrote, not a shared rule with an overlapping role.
  • create or modify navigation reports "Unchanged" when the write was elided, instead of "updated" on every run.
  • MDL-DEPR081 names the $currentObject binding its suggested form needs. Dropping the brackets alone rebinds a bare attribute, and the old message caused exactly that.
  • drop microflow M.F if exists; hints the correct order, and no longer adds a false "missing ;" after parser recovery.
  • A hyphenated icon name (Atlas_Core.Atlas.add-circle) gets a hint to quote the last segment: Atlas_Core.Atlas."add-circle".

Lint

  • MPR007 flags a user role that cannot open its home page. That case passed lint and check, then failed mxbuild with one CE2729 per widget, none of them naming the cause.

Devcontainer

  • The devcontainer builds with go.mod's toolchain (1.27.2) via GOTOOLCHAIN=auto. The image's 1.27.1 is still affected by the stdlib advisories

claude and others added 16 commits October 9, 2026 20:25
After `grant write (Country) on entity FieldService.Customer to
FieldService.Coordinator`, the Result line printed `read *` - the rights of
the shared FabUser/Coordinator/Engineer rule - while the grant had written a
separate rule for Coordinator alone.

formatAccessRuleResult picked the first rule naming ANY granted role with the
same XPath, but AddEntityAccessRule upserts by the exact role set plus XPath.
On the GRANT path the echo now selects by that same key (sameRoleSet mirrors
the backend's order-insensitive sameStringSet). REVOKE keeps the any-overlap
match, which it wants.

Finding: .claude/skills/fix-issue/findings/mdl-executor/2026-10-09-grant-result-line-describes-shared-rule.json

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PkPkaYM12u8yqMKNmzBgT
…ut a project

`mxcli check` with no project reported every property of a project's own
pluggable widget (`pluggablewidget '<id>' w (…)`) as "not recognized and
will be silently dropped on write", although exec writes them all and the
same check with -p is clean. 58 false warnings across the mxcli-ledger
scripts.

Cause: with no project the widget registry holds only the embedded
definitions, so the explicit id resolves to no definition. TypeIsGeneric is
set only for a bare-identifier type, so this form fell through to the
built-in static allow-list. MDL-WIDGET25 already returns early for an
explicit id with no project.

Fix: skip the built-in checks for any widget carrying an explicit widget id,
detected by a new explicitWidgetID helper now shared with MDL-WIDGET25. With
a project an unknown id is still MDL-WIDGET25. Control test: a built-in
`container c (bogus: 1)` still raises MDL-WIDGET07.

Finding: .claude/skills/fix-issue/findings/mdl-executor/2026-10-09-check-no-project-widget07-explicit-widget-id.json

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PkPkaYM12u8yqMKNmzBgT
Re-running `create or modify navigation Responsive ...` printed
"Navigation profile 'Responsive' updated." on every run, although
canon.Reconcile elided the write and no .mxunit changed. The handler
printed its sentence with fmt.Fprintf after UpdateNavigationProfile
returned, so it claimed a write it had no evidence for; the #890 sweep
moved security and settings onto ctx.reportWrite but missed navigation.

The update branch now reports through ctx.reportWrite, which says
"Unchanged navigation profile '<name>'" (via the run tally) when the
write was offered and elided. The kept-menu-action note follows the
write, as reportWrite's follow-up lines do elsewhere. Creating a profile
always writes and is unchanged.

Finding: .claude/skills/fix-issue/findings/mdl-executor/2026-10-09-create-or-modify-navigation-reports-updated-when-write-elided.json

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PkPkaYM12u8yqMKNmzBgT
…ough describe -> exec

A describe -> exec round trip of a Studio Pro page lost every design
property, class and style on its layout-grid rows and columns, and reset
row/column alignment. Measured on ledger MyFirstModule.Home_Web:
Forms$DesignPropertyValue entries 46 -> 33 ('Flex container' x7 on
columns, 'Column gap' x3 and 'Cards style' x3 on rows), and
LayoutGridRow.VerticalAlignment Center x6 came back None. check, exec
and mx check were all green.

Cause: none of the three layers carried it. parseLayoutGridRows read
only columns/weights/widgets; buildLayoutGridRowV3/ColumnV3 ignored all
properties but widths (the validator classified row/column as
slotDropped); layoutGridRowToGen/ColumnToGen hardcoded an empty
Forms$Appearance, alignment "None" and SpacingBetweenColumns true.

Fix: sdk/pages LayoutGridRow/Column gain Class, Style, DynamicClasses,
DesignProperties and alignment (row: Vertical/HorizontalAlignment,
NoSpacingBetweenColumns; column: VerticalAlignment). Describe reads the
row's and column's Appearance and alignments and prints them only when
set (`row (VerticalAlignment: Center, DesignProperties: (...)) {`), so a
plain grid describes as before. The builder types design properties
against the theme's LayoutGridRow / LayoutGridColumn groups (shared
designPropertyValuesV3, split out of applyWidgetAppearance), and the
validator checks them there instead of reporting them dropped. A
top-level `row`/`column` keeps its appearance on the wrapping container
only. Writers (modelsdk and mcp) write the carried values, defaults
unchanged when unset.

Finding: .claude/skills/fix-issue/findings/mdl-executor/2026-10-09-layout-grid-row-column-appearance-lost-on-describe-exec.json
(follows 2026-09-29-re-running-describe-page-output-resets-every-layout-grid).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PkPkaYM12u8yqMKNmzBgT
MDL-DEPR081 told the author to write `Visible: <expression> / Editable:
<expression>` — "same meaning". It is not: inside the brackets a bare
attribute is rooted in $currentObject, so dropping the brackets alone
rebinds it (`Visible: ["N1"]` stores $currentObject/N1, `Visible: "N1"`
does not). A hand migration from the message changed every notes-mode
cell in sudoku with check, exec, mx check and tests all green (sudoku
FINDINGS #63). fmt --upgrade and the Structural rewrite were already
right; the one-line message contradicted its own suggestion.

The entry's Canonical now names the binding. It is the text shown by the
check/exec warning, the mdl-2 refusal, the LSP, fmt notes, help and the
generated migration table (versions.md regenerated).

Finding: .claude/skills/fix-issue/findings/mdl-other/2026-10-09-depr081-message-canonical-drops-currentobject.json

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PkPkaYM12u8yqMKNmzBgT
…ter recovery

`drop microflow M.F if exists;` (SQL order) gave only `extraneous input
'if'`, and under `mdl 1;` a second error claimed the statement "has no
terminating `;`" — ANTLR's recovery ended the drop at the name and
discarded `if exists;`, and the mdl-1 terminator check read that
truncated statement (ledger FINDINGS #166).

enhanceErrorMessage now names the order (`drop microflow if exists
M.F;`). The error listener records the lines it reported on, and
ExitStatement does not add a terminator error on such a line: the
statement there is what recovery left, not what was written. A missing
`;` on a clean line is still refused.

Finding: .claude/skills/fix-issue/findings/mdl-visitor/2026-10-09-drop-if-exists-after-name-blames-missing-semicolon.json

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PkPkaYM12u8yqMKNmzBgT
…epaired

integration (roundtrip) failed with "no longer breaks getput — strike it
from knownFailures" for WorkflowCommons.Snip_UserTask_NameColumnWithIcon
and Snip_WorkflowJumpToDetails. Both pass getput at a1f0463 and still
fail at its parent 4b1cfde: carrying layout-grid row/column appearance
and alignment through describe -> exec is what repaired them. The
allowlist may only shrink.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PkPkaYM12u8yqMKNmzBgT
`Icon: Atlas_Core.Atlas.add-circle` failed with an error pointing at a
dot (or `no viable alternative` on a widget), and quoting the whole name
read as a stray string; neither said what to write, and it cost the
ChipCoV6 build two retries. The grammar is right — an icon is a
qualified name and `add-circle` is not an identifier — so the fix is a
source-line hint naming `Atlas_Core.Atlas."add-circle"`, for menu items
and widget icons, unquoted or quoted whole.

Finding: .claude/skills/fix-issue/findings/mdl-visitor/2026-10-09-hyphenated-icon-name-no-hint.json

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PkPkaYM12u8yqMKNmzBgT
A page or snippet variable's default is a Mendix expression, but MDL took
it in a string whose content was the expression: `$show: Boolean =
'true'`. It is now written bare (R5) — `= true`, `= if (3 < 4) then true
else false`, `= 'Price' + ' list'`, `= Module.Enum.Value` — in create
page, create snippet and `alter page … add variables`.

mdl 1 is frozen, so the string form keeps its meaning under every
language version and is the deprecated alias MDL-DEPR086 (refused from
mdl 2), with the `fmt --upgrade` rewrite. A default that is itself a
string (`'''abc'''`) or empty has no bare spelling yet — the bare `'abc'`
is the alias — and is not reported. describe writes the bare form when it
reads back as the same default.

The example scripts were converted with fmt --upgrade itself; docs,
syntax help, skills and the generated migration table follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P65SqmwwvbWdJVRwhYiMQw
The R2 brace/paren tests used `$show: Boolean = 'true'` as their
canonical form, which MDL-DEPR086 now reports, so each case recorded two
deprecations instead of the one it exercises, and describe's expected
output was the quoted form. The defaults are written bare.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P65SqmwwvbWdJVRwhYiMQw
The generic ALTER PAGE syntax help and the grammar comment, both changed
on main since, still showed `$show: Boolean = 'true'` (MDL-DEPR086).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P65SqmwwvbWdJVRwhYiMQw
A user role none of whose module roles is allowed on the home page it lands
on passes `mxcli lint` and `check --references`, then fails mxbuild with one
CE2729 per widget on that page ("No read access to attribute ... for user
role 'X' (with no roles defined in module 'M')") — none of which names the
cause. ChipCoV6 hit it with the template's generic `User` role left in place
after the Responsive home page moved to a new module (FINDINGS.md: 10x
CE2729 in docker check).

MPR007 only checked that a navigation page has some allowed role (CE0557).
It now also resolves, per navigation profile and user role, the effective
home page (the role-based entry for that role, else the profile default)
and warns when none of the role's module roles is allowed. A microflow home
page is checked against the microflow's allowed module roles. Skipped at
security level Off; a page with no allowed roles at all is left to the
existing CE0557 report. The guest role is an ordinary user role in the
list, so it is covered without special-casing; nothing is exempted by name.

Verified on a copy of ChipCoV6 with `create user role TmpUser (ModuleRoles:
(System.User, Administration.User))`: mxbuild 11.15.0 reports 10x CE2729,
lint now reports one MPR007 warning naming TmpUser, Responsive and
FieldService.Home_Dashboard; the unmodified project (Administrator, FabUser,
ServiceCoordinator, FieldEngineer) and Ledger report no new MPR007.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012PkPkaYM12u8yqMKNmzBgT
The devcontainer was on go:dev-1.26-bookworm while go.mod and CI moved to
toolchain go1.27.2 (#1064) for five stdlib security fixes
(GO-2026-6603..6608, fixed in 1.26.9 / 1.27.2). The image sets
GOTOOLCHAIN=local, so local builds ignored the pin and used the image's
Go: 1.26.4 here.

Bumping the tag alone is not enough: dev-1.27-bookworm ships 1.27.1,
which is still affected, and the image has no patch-level tags. So also
set GOTOOLCHAIN=auto, letting go.mod's toolchain line — the same pin CI
uses — select the version, now and on future bumps.

Verified by building this Dockerfile and running `go version` against the
repo's go.mod:
  this image          GOTOOLCHAIN=auto   go1.27.2 (downloaded)
  base image (control) GOTOOLCHAIN=local go1.27.1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(pages): write a page variable's default as a bare expression
@ako
ako merged commit 22d9ea6 into mendixlabs:main Oct 10, 2026
15 checks passed
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.

2 participants