Skip to content

fix(navigation): every menu item action round-trips; native profiles refuse what they cannot write (#980) - #985

Merged
ako merged 16 commits into
mainfrom
fix/980-navigation-menu-actions
Oct 4, 2026
Merged

ako merged 16 commits into
mainfrom
fix/980-navigation-menu-actions

Conversation

@ako

@ako ako commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Closes #980

describe navigation → exec no longer drops or changes a menu item action. Every action kind round-trips on TestApp. Describe → exec writes nothing (the unit file is byte-identical), describe again gives identical text, and mx check (11.14.0) reports 0 errors for each kind written fresh.

What changed (one commit each)

  1. Guard (4811f3271)
    • The reader keeps each menu item's stored action bytes.
    • create or modify navigation and create or modify menu pair each script item with its stored item by caption path.
    • When the script's item states no action and describe cannot print the stored one, exec keeps the stored action and says which one it kept. Describe flags such an action with a -- comment.
  2. Sync constraint layout (b473e9f08)
    • Found while adding navigation to the round-trip harness: describe prints a multi-line sync constraint on one line, so the rewrite stored the one-line text and changed TestApp's TabletOffline on every re-run.
    • A constraint that differs from the stored one only in whitespace outside string literals now keeps the stored text.
  3. Full fix, modelled on Describe round trip: delete close page, $[%…%] returns, navigation-list items (#950) #959 (3bea9594f)
    • Describe: a stored action is rendered with renderClientActionMDL and its settings renderer, the same code a button's action goes through.
    • Grammar: navMenuAction : actionExprV3. This is additive, because the three old forms are alternatives of actionExprV3. The visitor refuses kinds a menu item cannot carry (save, delete, close page, complete task, a dynamic open link).
    • Exec: the page builder builds the action and the widget serializer (clientActionToGen) writes it, for both navigation and menu documents.
    • Serializer fixes, so its output matches what Studio Pro stores:
      • OutputMappings on Forms$CallNanoflowClientAction (78 of 78 in TestApp and PedApp)
      • DisabledDuringExecution on a menu item's Forms$NoAction
      • AlternativeText and an empty Items list on a menu item (Menus$MenuItem)
    • No MDL spelling: a page title override, a link type other than Web and NumberOfPagesToClose2. Describe flags each one. A rewrite keeps the stored action when the action it builds is otherwise equal to the stored one (ignoring $IDs and those keys).
    • Standalone menus: they share printMenuMDL and the writer, so they are covered too. create or modify menu also stops writing glyph and image icons as no icon.
    • MCP backend: it refuses a menu action it cannot write. Before, it stored no action.
    • Round-trip harness:
      • Navigation profiles now join the TestApp and PedApp round-trip harness.
      • Struck from the allowlists: Atlas_Core.Phone_Menu and Tablet_Menu (both fixtures), and page WorkflowCommons.ConflictedWorkflowDefinitionView_ActionConfirmation, whose only loss was the nanoflow OutputMappings.
  4. check --references and System images (92f1a7024): Icon: image System.Images.Save is no longer refused. The System module is the platform's, so no project stores its collections, and the reference is left to mxbuild.
  5. Native profiles (a51134399)
    • Exec refuses, before writing anything, the clauses the native writer used to drop without a word: a { } menu block (the bottom bar), login page, not found page and on sync error.
    • Native sync ( … ) is now written.
    • home nanoflow: a new keyword (additive). home microflow on a native profile still works but warns. home nanoflow on a web profile is refused.
    • Reader: it now reads a bottom-bar item's action and icon.
    • Describe: it lists the bottom bar as comments, so its output re-runs.
    • Catalog: schema version → 21.
  6. Docs (23463322a): updated the navigation syntax help, the manage-navigation skill, the docs-site navigation and menu reference pages and the quick reference. Added a new example, mdl-examples/bug-tests/980-navigation-menu-actions.mdl.

GUID and identity: a navigation item has no GUID. Its $IDs are carried over by canon.Reconcile, and an unchanged re-run writes nothing. On a TestApp copy, the unit is byte-identical after describe → exec.

Test plan

  • make build
  • go test ./mdl/executor/ ./mdl/backend/... ./mdl/visitor/ ./mdl/types/ ./mdl/catalog/ ./mdl/ast/ ./modelsdk/mpr/ ./mdl/grammar/ ./cmd/mxcli/...: ok
  • go test -tags integration ./mdl/roundtrip/ -run 'TestTestAppRoundTrip$|TestPedAppRoundTrip$|TestNavigationMenuActionsRoundTrip_980|TestDescribeReExecutes_950|EditIsWritten': ok
    • The new TestNavigationMenuActionsRoundTrip_980 adds one item per action kind to TestApp's Responsive profile, in the shape Studio Pro stores (nanoflow and microflow with every setting, open link, create object then show page, link type Email, a title override). It then checks:
      • GetPut: nothing is written.
      • PutGet: the second describe is identical.
      • Built without carry: after every caption is renamed, so no stored action can be carried, each action is stored equal to Studio Pro's shape apart from $IDs.
  • make check-conformance, make lint, make check-findings, make check-mdl, make check-skill-mdl: ok
  • End to end on TestApp copies (CLI):
    • Describe → check --references → exec → describe of the whole navigation document: the unit is byte-identical, and the second describe is identical.
    • 980-navigation-menu-actions.mdl, which writes every kind fresh to navigation and to Atlas_Core.Phone_Menu: check --references passes, exec passes, and mxcli docker check reports 0 errors. Describe → exec of the result reports "Unchanged", and no file changed (md5 of all mprcontents).

Revert checks

Fix removed What failed
KeepAction set in the executor TestNavigationRewrite_KeepsAnActionMDLCannotExpress: KeepAction empty for 'Reports' and for the sub-item
Describe note for an inexpressible action TestDescribeNavigation_FlagsAnActionMDLCannotExpress
Writer writes KeepAction TestNavMenuAction_WritesAKeptActionVerbatim: wrote Forms$NoAction
Shared renderer in printMenuMDL TestNavigationMenuActionsRoundTrip_980: "describe lost …'s action" for 5 kinds, plus both notes missing
Carry when only the masked keys differ …_980: GetPut wrote the navigation unit, and PutGet differs
OutputMappings default on the nanoflow action …_980: GetPut, and "NF settings built from MDL differs from Studio Pro's shape"
Sync constraint layout carry TestOfflineWriteKeepsTheStoredLayoutOfAnUnchangedConstraint. Before the fix, the TabletOffline CLI re-run changed Constraint
Forms$NoAction DisabledDuringExecution / Menus$MenuItem defaults Measured before the fix: navigation Responsive described → exec rewrote 3 NoActions, and menu Atlas_Core.Phone_Menu / Tablet_Menu broke GetPut (the harness then said "no longer breaks getput" once they were fixed)
System collection skip TestIconIndexCheck_SystemCollectionIsNotRefused: "unknown image collection System.Images"
Native clause refusal TestNativeProfile_RefusesWhatItsWriterCannotApply (wrote=true, err=nil for all 4 clauses), TestNavigationHomeNanoflow
Native sync write TestNativeProfile_WritesSync

Follow-ups (not changed here)

  • No MDL spelling yet for a page title override on a widget or menu show-page action, an open-link type (Email/Call/Text), or NumberOfPagesToClose2. They are kept only while the item is unchanged, and a renamed item loses them. Describe flags each one. Adding them needs a syntax decision.
  • Native bottom bar: it is read and described but not written. Writing NativePages$BottomBarItem needs a Studio Pro reference. No local fixture has a native profile, so the reader is pinned with a hand-built document.
  • The catalog's navigation_profiles.HomePageType still says MICROFLOW for a native nanoflow home.

🤖 Generated with Claude Code

ako and others added 16 commits October 4, 2026 18:52
formatDecimal(x, '0.00') follows the user's language, so a Dutch user got
12,50 and invalid JSON. Use toString(round(x, 2)), or formatDecimal with a
hyphenated locale; explain the silently-ignored underscore tag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…json (#982)

The run --local hint 'mxcli oql -p …' failed on a non-default --admin-port
(cannot connect … localhost:8090), and mxcli log did the same. Both now take
the port and password from a live .mxcli/run-local.json for any flag not given.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ilt JSON (#982)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#980)

describe navigation printed a nanoflow / open-link / create-object menu
item with no OnClick, and exec of that description stored Forms$NoAction:
TestApp's 'Item 4' lost its nanoflow call at exit 0. The reader now keeps
each item's stored action bytes; create or modify navigation and create or
modify menu pair script items with stored ones by caption path and carry a
stored action describe cannot print when the item states none, reporting
each carried action. Describe flags such an action with a comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…refuses

MDL033 comparison as a select column (CE0174), MDL034 aggregate over a
grouped column (CE0174), MDL035 plain column not grouped (CE0174),
MDL036 non-aggregated expression not in the GROUP BY (passes mxbuild,
PostgreSQL 42803 / HSQLDB 42574 at runtime) - errors in ValidateOQLSyntax.
MDL037 literal aggregate argument (HSQLDB 42567, warning) and MDL038 bare
integer/string literal column (info) in ValidateOQLPortability, which only
check and the LSP run. Part of #981.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
String concatenation (r.Name + ' x') is a derived String(200) in mxbuild;
string / string(100) declarations are CE6770 and now MDL031. A view
attribute declared autonumber over an AutoNumber column (CE6770) is
refused under mdl 1 and warns MDL-V1-VIEWAUTONUMBER without the header
(ADR-0011); check's reference tier now runs under the script's language
version. Part of #981.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
write-oql-queries: a view entity has no ID (count a non-null column), the
GROUP BY / comparison / HSQLDB literal table, String(200) concatenation,
AutoNumber -> Long.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sum(0.0) and sum(1.5) fail on HSQLDB with 42567 like the integer forms;
only a decimal select COLUMN is cast by Mendix (MDL038 still skips it).
avg(1) runs on HSQLDB and stays unflagged. Part of #981.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nt (#980)

Studio Pro lays an offline sync constraint out over several lines; describe
prints it on one and the rewrite stored that text, so every describe -> exec
of an offline profile (TestApp's TabletOffline) rewrote the navigation
document. A constraint equal to the stored one apart from whitespace outside
string literals now keeps the stored text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Model a menu item's action the way #959 did for navigation-list items:

- reader keeps the stored action document; describe renders it with
  renderClientActionMDL (call nanoflow, open link, create object, settings);
- OnClick takes actionExprV3 (additive: the three old forms are among its
  alternatives); the visitor refuses kinds a menu item cannot carry;
- exec builds the action with the page builder and writes it with the
  widget client-action serializer, for navigation and menu documents.

The serializer now matches Studio Pro on the shapes it missed: OutputMappings
on Forms$CallNanoflowClientAction, DisabledDuringExecution on a menu item's
Forms$NoAction, and a menu item's AlternativeText and empty Items. What MDL
cannot spell (title override, link type, pages to close) is flagged and kept
while the built action is otherwise equal to the stored one.

Navigation profiles join the TestApp/PedApp round-trip harness; Atlas_Core's
Phone_Menu / Tablet_Menu and one page are struck from the allowlists. The MCP
backend refuses a menu action it cannot write.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…980)

describe navigation prints TestApp's sign-out item as
`Icon: image System.Images.Save`, and check --references refused it as an
unknown image collection, so the description only re-ran with --no-check.
The System module is the platform's and no project stores its collections;
a reference into one is left to mxbuild.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#980)

The native profile writer applied home pages only, and exec reported
"updated" while dropping a menu block (the bottom bar), login and not-found
pages and on sync error; those are refused now, and the sync block is
written. A native nanoflow home gets its own keyword, `home nanoflow`
(additive; `home microflow` on a native profile still runs, with a
warning). The reader takes a bottom bar item's action and icon, and describe
lists the bar as comments so its output re-runs. Catalog schema 21.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mits (#980)

The navigation syntax help, the manage-navigation skill, the docs-site
navigation and menu references and the quick reference describe OnClick as a
button's action expression with its settings, the kinds a menu item refuses,
what describe flags and a rewrite keeps, home nanoflow, and what mxcli does
and does not write for a native profile. The native example no longer shows
a menu block, which is now refused. Adds bug-test 980.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ako
ako merged commit 8c08c8f into main Oct 4, 2026
33 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.

Navigation describe → exec silently drops nanoflow / open-link / create-object menu actions and microflow/page action settings

1 participant