Repository navigation
Sync ako/mxcli: diff-local hunks, run --local hangs, playwright check, admin password from MDL, widget property refusals, QUAL004 callers - #1665
Merged
Conversation
Every QUAL004 finding printed its location as `at M.M.NAV_Home`, and so did CONV001-010, the SEC rules and most other bundled Starlark rules: they pass `document_name=<x>.qualified_name`, while Location.QualifiedName() prefixes the module to DocumentName, which it takes to be the short name. The Go rule missing_translations does the same, and CONV018's module-level finding printed `at Sales.Sales`. QualifiedName() is the one place a location becomes a name (text, Markdown, SARIF, `lint -d`), so it now accepts both spellings: a DocumentName that already starts with "<module>." is returned as is (a Mendix document name cannot contain a dot, so the prefix is always the module), and a module-level finding naming the module itself prints the module once. Fixing the ~30 rule files instead would leave every project's stale `mxcli init` copies, and every user-written rule, still doubling. Verified: TestLocationQualifiedNameDoesNotRepeatTheModule (with controls for a document named like its module and a module name that prefixes the document's) and TestShippedRuleLocationPrintsTheModuleOnce (the shipped QUAL004 rule through the text formatter) both fail with `at Sales.Sales.Big_MF` when the change to linter.go is reverted. Found while reproducing #1484. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m anywhere (#1484) A microflow started only from the navigation — a profile's home microflow, or a menu item's `call microflow` — was reported as "is not called from anywhere. Remove if unused", while `mxcli refs` listed its `home_page` / `menu_item` edge (upstream mendixlabs#1579; the 4 NAV_ findings left in #1639). Cause: orphaned_elements.star decided "has a caller" from its own copy of the reference vocabulary, MICROFLOW_ENTRY_KINDS. PAGE_ENTRY_KINDS had home_page and menu_item; the microflow list did not. It is the fourth time that list fell behind the catalog (datasource/action/calculate, schedule, settings/publish, event), so adding the two kinds would only reset the clock. Fix: the rule keeps no kind list. A microflow or page is used when any edge in the reference graph points at it — what `refs` and GRAPH_DEAD_ASSETS already read; no kind that targets a microflow or a page means anything but "this runs / opens it", so no exclusion list is needed either. Drift is guarded behaviourally: catalog.RefKinds is held complete against the RefKind constants, and TestQUAL004CountsEveryRefKind drives every one of them at a microflow, a nanoflow and a page through the shipped rule (an unreferenced microflow is the per-kind control), so a kind added later is tested the day it is declared and a reintroduced allowlist fails by name. The two catalog tests that pinned the old lists are replaced by it; `schedule` edges are among the kinds driven. Verification: - TestQUAL004CountsNavigationAsACaller (controls: an unreferenced microflow and page are still reported, an ACT_ microflow is still exempt) fails with "QUAL004 reports M.NAV_Home / M.NAV_Orders" when the rule change is reverted; TestQUAL004CountsEveryRefKind fails for every kind, and the RefKinds guard fails when a constant is left out. - Real 11.13 app (blank app + navigation from the repro), BASELINE binary with only the rule swapped: NAV_Home and NAV_Orders drop out of QUAL004; the unreferenced control microflow M.Unused and page M.ItemEdit are still reported; ACT_Entry still exempt. Repro: mdl-examples/bug-tests/qual004-1484-navigation-microflows.mdl. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ng (#1512) After `alter settings constant … in configuration …` or `alter settings runtime (BcryptCost: 11)`, `mxcli diff-local` printed only "Summary: 0 new, 1 modified, 0 deleted", and `--format struct` said "(no changes)" (mendixlabs#1602). Cause: bsonToMDL had no case for Settings$ProjectSettings, so the unit fell to the generic rendering — two comment lines naming the type, the same at every revision. The same silence hit every unit whose change lies outside what its renderer prints: a probe of one statement per kind on a git-initialised 11.13 app found navigation, project security (admin user, user roles), module security, a page's and a published REST service's allowed roles, an entity index and a constant's default value all counted and blank. Fix: - The settings unit renders with DESCRIBE SETTINGS' own writer (writeProjectSettingsMDL, split out of describeSettings) over a parse of each revision (new Backend.ParseProjectSettingsFromRaw, RawParts included, so the stored-property filter matches describe). Configuration constant values are masked, as the issue asks: each side is rendered knowing the other's value, so a change still shows as `value <masked: old value>` / `value <masked: new value>`; an unchanged or one-sided value is `<masked>`. The mask is not a string literal, so pasted output fails to parse instead of storing it. - The class: git has already said the bytes differ, so a modified unit whose two renderings are equal is printed — in every format — as one line naming the property paths that changed, never their values: "Modified: ModuleSecurity M: changed in properties the MDL rendering does not show: ModuleRoles (0 -> 1 items)". diff-local now prints via WriteDiffResults, the writer `mxcli diff` uses for the same situation, and the path walker moved from mdl/scriptdiff into the executor (ChangedPaths) so both commands share it. The walker no longer counts Mendix's leading typed-array marker as a list item (a first grant read "1 -> 2 items"), which corrects `mxcli diff`'s note too. Verification: real-backend tests drive diff-local over a copy of the v2 fixture with git answered from a unit snapshot — masked constant change and addition, runtime change in unified/side/struct, the note for an unrendered unit in all three formats; controls: an elided re-run reports no changes, and an attribute change renders byte for byte as on 97e1cce. Revert proofs: without the settings case and the note the tests print exactly the reported "Summary: 0 new, 1 modified, 0 deleted" / "(no changes)"; without the mask they print 'secret123'; without the marker skip they read "1 -> 2 items". Real app (11.13, git): the issue's script now shows the BcryptCost and masked-constant hunks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s not found (#1486) `grant access on published rest service M.Svc to M.Role` failed with "published rest service not found: M.Svc" when the service was created with a `folder '…'` clause earlier in the same script, and exec rolled the whole script back; `check -p --references` passed. Mirror of mendixlabs#1581. Trigger, measured on 11.13.0 with the baseline binary: no folder, a folder that already existed (made by a previous exec), or the grant in a second exec all resolve. Only a folder the CREATE itself makes fails. Cause: exec caches the container hierarchy (module <- folder <- folder) and resolves every document's module by walking up from its ContainerID. The CREATE's existence check built that cache, then resolveFolder -> createFolder made the folder and nothing recorded it, so the walk stopped at an unknown folder, the module name came back "" and the lookup missed. Every other container-changing write (create module, move document, move/drop folder, applyDocumentFolder, rename module) already invalidated the cache; folder creation was the gap. Fix: createFolder records the new folder in the cached hierarchy (ContainerHierarchy.addFolder). The page builder's own folder creator now delegates to it, leaving one Backend.CreateFolder call site in the executor, which TestFolderCreationHasOneCallSite holds. Same mechanism, fixed by the same change (audit: 19 doctypes, each created in a new folder then looked up by name, warm and cold cache): published REST service, consumed REST service, scheduled event, task queue and regular expression failed on baseline; the other 14 passed because their CREATE invalidates the hierarchy afterwards or their lookup does not use it. The worse half: a re-run CREATE OR MODIFY of any of the five in the same script missed its own document and silently created a second one with the same name (measured: 2 services, 2 queues, 2 regexes, 2 rest clients, 2 scheduled events); now "Unchanged". check had nothing to predict: its grant-ref validation already tracks script-created documents; exec's cache was what was wrong. Verification: - mdl/executor/hierarchy_created_folder_test.go: grant+revoke after a create in a new folder (module-root control), re-run CREATE OR MODIFY is one service, missing service still refused, the cached hierarchy resolves folders made by resolveFolder and the page builder, and the single-call-site guard. Revert proof: with the fix removed the four new tests fail with "published rest service not found: M.PingApi", "2 services named M.PingApi" and an empty module/path; controls pass. - Real 11.13.0 app: the issue's script now execs, describe shows the service in 'Api/Services' with the grant, mx check 0 errors. mdl-examples/bug-tests/rest-grant-1486-service-in-new-folder.mdl execs cleanly (baseline: not found, rolled back) and mx check reports 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ntication microflows dead (#1639) `mxcli refs Mod.Read_Drivers` said "no references found" for a microflow that is a published OData resource's `ReadMode: microflow`, and likewise for the service's `Authentication: (microflow X)`; `impact` agreed and QUAL004 advised "Remove if unused" — 35 of the reporter's backend's 43 QUAL004 findings. Half 1 of the issue (QUAL004 ignoring references the catalog already has) was, after the reporter's re-measurement, the navigation menu-item case alone; it is fixed by the #1484 commit, which makes the rule count every edge. This commit is half 2: the edges themselves. Cause: buildODataServices catalogued the service and emitted no edge for any microflow it names — entity-set read/change modes, published OData actions, the authentication microflow. Auditing the sibling services (every `*Microflow*QualifiedName()` in modelsdk/gen against the builders) found the same gap where the reader already has the name: a published REST service's authentication microflow, a business event service operation's handler (stored in business_events_data, dropped), and a consumed OData service's configuration / headers / error-handling microflows. Fix: the service builders collect one edge per distinct microflow (builder_service_refs.go) and buildReferences emits them, from the service (new source types PUBLISHED_ODATA_SERVICE, PUBLISHED_REST_SERVICE, BUSINESS_EVENT_SERVICE, CONSUMED_ODATA_SERVICE, equal to their objects ObjectType, catalog id in SourceId). Kinds are reused, not minted, so `show callers`, the analysis graph and QUAL004 need no list change: `publish` (a published service runs it), `event` (an event handler — entity or business event), `call` (the consumed service calls its configuration microflow, as a workflow calls its handlers). CatalogSchemaVersion 28 -> 29 so cached catalogs rebuild. Verification: - builder_service_refs_test.go pins each edge, the SourceId join, the dedup and the no-microflow modes; with the collection hooks reverted every edge test gets [] and GRAPH_DEAD_ASSETS lists Read_Rows and AuthenticateApiClient again (unreferenced control still listed). - Real 11.13 app, same model, baseline vs fixed binary: `refs` for the read, authentication and action microflows of a published OData service, a published REST service's authentication microflow and a business event handler goes from "no references found" to one publish/event row each; `show callers` names the service; QUAL004 and GRAPH_DEAD_ASSETS drop them; the unreferenced control is still reported. On ako/TestApp (Studio Pro reference) the three published OData actions gain `publish` edges. No Studio Pro document with a read or authentication microflow was at hand, so those two read paths are verified on mxcli-written documents (keys match generated/metamodel). Not fixed, same symptom, different mechanism (no reader or no table): published SOAP web services, import/export mapping custom-handler microflows, ProjectSecurity.SignInMicroflow, a microflow's ConcurrencyErrorMicroflow, the navigation not-found page. Repro: mdl-examples/bug-tests/catalog-1639-service-microflow-refs.mdl. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or clause (#1448) A call in a test body that already had an error-handling clause (`on error rollback`, `on error continue`, a custom handler) got the runner's `ON ERROR BEGIN … END ERROR` appended as a second one. The generated MDL did not parse ("mismatched input 'ON' expecting ';'", plus a misleading hint about `Error` being a keyword) and the run stopped at injection, before the app started. Upstream: mendixlabs#1550. Cause: attachOnError (endpoint runner) and its two copies in the legacy after-startup runner wrapped every line startsErrorRaisingCall matched, unconditionally. Their line-based join also broke on a custom handler (the handler body's first `;` ended the "statement") and on a trailing comment. Fix: - One attachOnError for both runners, with and without @throws. It parses the body inside the generator's own wrapper and language version (visitor.FlowStatements, new) and reads each call's own onErrorClause from the tree — not text, so a clause on a later line counts and `on error` in a string, a comment or a nested handler does not. The set of wrapped statements is now a set of grammar rule names, pinned to the grammar. - A call with `on error continue` or a custom handler keeps it verbatim and gets no second handler. `on error rollback` is Mendix's default spelled out (the same ErrorHandlingType as no clause), so it is replaced by the runner's handler, which also rolls back: same model, same verdict. - Keeping custom handlers opened a false green that only the runtime showed: a handler that ends normally rejoins the flow past every statement reading the failed call's output — the @expect checks — and the test returned PASS with nothing evaluated. Each assertion now counts itself in both branches of its decision, and a guard after the last fails a short count ("not every assertion was evaluated"). Both runners. - Legacy log parser: a test with a RUN line and no verdict read as PASS (StatusPass is the zero value). A re-raising handler ends the legacy runner exactly there; it is now an ERROR that says so. Verification (Mendix 11.13.0, --local --db-type hsqldb, the issue's setup): the baseline binary stops with the reported parse error; the fixed one runs mdl-examples/bug-tests/test-runner-1448-own-error-handler.test.mdl: plain/rollback throwing FAIL "exception during execution: boom: a"; continue FAIL on its assertion; custom-handler-ends-normally FAIL "not every assertion was evaluated" (PASS before the guard); re-raise ERROR "boom: a"; @throws plain/rollback PASS, continue/custom FAIL "expected an exception but none was thrown", re-raise ERROR; the report's two statements PASS; an assertion on what the handler set PASS. --legacy-runner gives the same verdicts; its re-raise case was PASS and is now ERROR. Revert proofs (stubbing each guard): the always-attach stub reproduces "mismatched input 'ON'" in the unit tests; the rollback, counter and RUN-without-verdict stubs each fail their test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After `grant read *, write * on entity Shop.Customer to Shop.User`, `mxcli diff-local` counted the domain model as modified and printed no hunk (mendixlabs#1630); `describe entity` showed the new rule. Cause: domainModelBsonToMDL rendered each entity's attributes and the associations from the raw BSON map, but never the entities' AccessRules, so an access-only change rendered the same at both revisions. Fix: each entity is now followed by its access rules, written by outputEntityAccessGrants — the writer DESCRIBE ENTITY uses — over a parse of that revision of the unit (new Backend.ParseDomainModelFromRaw, the gen->semantic conversion GetDomainModel uses). No second grant renderer: a test pins that every `grant` line `describe entity` prints, where-clause and member lists included, appears verbatim on diff-local's new side. A parse failure is printed as a comment rather than dropping the rules silently. -grant read * on entity M.Item to M.User; +grant read *, write * on entity M.Item to M.User; Verification: real-backend tests over a copy of the v2 fixture (git answered from a unit snapshot) for a changed, an added and a revoked rule, unified and struct; a backend test that the raw parse yields the same access rules as GetDomainModel for every domain model in the fixture. Control: an entity without rules still renders byte for byte as on 97e1cce. Revert proofs: without the grant rendering the tests fail with "Modified: DomainModel M: changed in properties the MDL rendering does not show: Entities[Item].AccessRules[0]…" (the #1512 note catching it), and with that note also removed with exactly the reported "Summary: 0 new, 1 modified, 0 deleted". Real app (11.13, git): the issue's script shows the -/+ grant pair; mx check 0 errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…roflow applies entity access (#1654) `mxcli test --local` generates MxTest.RegisterEndpoint, the startup microflow that registers the test endpoint and then calls the project's own after-startup microflow. It was written without "apply entity access", and MxBuild refuses a microflow that does not apply entity access calling one that does (CE0114). In any project whose after-startup microflow applies entity access the build failed, no test ran, and the error said "These errors are in the project, not in this run's tests" about a microflow mxcli generated. Upstream: mendixlabs#1645. Measured direction (mx check, Mendix 11.13.0, security Off and Production): non-applying -> applying is CE0114; applying -> non-applying and applying -> applying (with a Java action call beside it) are 0 errors, and an applying microflow is accepted as the after-startup microflow. MDL-SEC22 records the same table for 11.14.0. Fix: - GenerateEndpointMDL writes `@applyentityaccess` on RegisterEndpoint. Since an applying caller may call either kind, a constant serves every project with nothing read from the user's microflow (the suggested mirror would have added a second scrape of describe output). It governs only the flow's own activities: the Java action ignores it, the chained microflow runs with its own setting. Also covers `run --local --test-endpoint`, which shares the generator. - buildFailureHint attributes an error located in MxTest.RegisterEndpoint or MxTest.RegisterTestEndpoint to mxcli — "not part of your project: mxcli generated it for this run … a defect in mxcli … please report it" — with --skip-app-startup as the escape hatch, and says "in the project" only for the errors that are. Verification: on a blank 11.13.0 app with mdl-examples/bug-tests/test-runner-1654-setup.mdl (startup microflow applies entity access and leaves a marker), the baseline binary fails with the reported CE0114; the fixed one passes both tests, the second proving the startup microflow ran at boot. Controls: the same run with --skip-app-startup fails that test ("expected $Count > 0, actual: 0") — the test consumes the marker so an earlier boot's cannot pass it; a non-applying startup microflow still passes both. A binary with only the attribution half shows the new message on the live CE0114. Revert proof (patch method): with endpoint.go and build_attribution.go checked out, TestRegisterEndpointAppliesEntityAccess and TestBuildErrorInGeneratedStartupFlowIsMxclis fail; the project-only control passes either way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on a textbox (#1698) `textbox tb (Attribute: Name, Caption: 'Item name')` passed check and exec, and the text box was written with no label (mendixlabs#1651): an input takes `Label:`, `Caption:` is a button's. MDL-WIDGET07 judged every built-in widget against the UNION of all built-in widgets' vocabularies, so a key valid on any widget passed on all of them - the class behind mendixlabs#1307, #1465, #1582 and #1643. Measured on the per-widget sets, the same hole drops `Visible:` on a snippet call, scroll container, placeholder, layout header or menu widget (their stored types have no ConditionalVisibilitySettings), and every appearance key but Class on a scroll-container region; layouts were walked by no widget rule at all. Fix: every built-in page element - each buildWidgetV3 keyword, and the children a parent builds itself (regions, layout-grid rows and columns, navigation-list items, a data view's footer, a list view's specialization template) - has the set of properties its builder reads, plus what buildWidgetV3's tail writes for its stored type (appearance always, Visible only where the gen type can hold it). nativeWidgetPropRefusals is the one verdict: check reports it (in place of MDL-WIDGET07 for these kinds, and now for layouts too) and exec refuses on it in buildWidgetV3 and in each parent builder, so `exec --no-check` cannot drop either. A new rejection, gated per ADR-0011 like MDL-V1-TABPAGEPROP: MDL-WIDGET52 under `mdl 1;`, an MDL-V1-WIDGETPROP warning without the header. The message names what was meant (Caption on an input -> `Label:`, Label on a button -> `Caption:`, a typo -> did you mean) and lists what the widget takes. describe prints only a region's Class, the one appearance key a region is read and written with. The sets cannot drift from the builders: TestNativeWidgetProps_MatchBuilderReads taint-walks the builders' source (go/parser, following the widget argument through helpers) and requires each kind's reads to equal what its builder reads, both ways; _TailMatchesGen ties Visible to the gen writer's setters; _DescribeEmitsOnlyAccepted holds describe's cases to the same sets. Verification. Blast radius, measured before choosing a refusal: 0 refusals across every non-.fail doctype, bug-test and deprecated-alias script; 0 across all skill and docs-site MDL blocks; 0 in describe -> check of every module of a blank 11.13 app, ako/TestApp and PedApp, and of 19 doctype page and layout scripts exec'd into a fresh app. The one script that changes is widget-unknown-property.mdl, whose two typos are now refused; it becomes a .fail.mdl. On a fresh 11.13 app: check fails with MDL-WIDGET52 naming `Label:`, exec and exec --no-check write nothing; the Label: version writes the label and mx check reports 0 errors; without the header it warns and writes what it wrote before. Revert proof: with the verdict stubbed all seven behaviour tests fail with the reported symptom (no violation); a table entry the builder does not read, or one it lacks, fails the drift test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1703) A responsive layout's scroll container has a LayoutMode: Headline (the top region runs the full width) or Sidebar (the left region runs the full height). describe layout did not print it and create layout could not write it, so the documented describe -> rename -> exec copy of Atlas_Core.Atlas_SideBar (stored Sidebar) came out Headline - a different frame, with Atlas's sidebar CSS positioned for the other one (mendixlabs#1659). mx check reported 0 errors either way; the copies were Headline only because canon fills the absent key with Studio Pro's measured default. Fix: pages.ScrollContainer carries LayoutMode, with the members (Headline | Sidebar, generated/metamodel's PagesLayoutMode, tested against it) and a case-insensitive canonical spelling in sdk/pages shared by the builder and the mutator. buildScrollContainerV3 reads it and refuses any other value, the modelsdk writer sets it when stated, `alter layout ... set (LayoutMode: ...) on <scrollcontainer>` writes it on a stored scroll container that carries the key (never inventing one), and describe prints it when it is Sidebar. The policy comes from the stored documents: of the 17 Atlas_Core layouts with a scroll container on 11.13, 8 are Sidebar and 9 Headline, and an unset key reads as Headline - so a layout that never set it is described and written exactly as before. Before this commit the per-widget property check of #1698 refused `LayoutMode:` (MDL-WIDGET52) rather than dropping it; now the scroll container's set takes it. Verification: on a fresh 11.13 app, describe Atlas_SideBar prints `scrollcontainer layoutContainer (LayoutMode: 'Sidebar') {`, the renamed copy passes check, execs, stores LayoutMode "Sidebar" (baseline: "Headline" with and without the property) and describes identically; the doctype layouts and the bug-test script exec, `alter layout` flips Headline -> Sidebar, and mx check reports 0 errors. On PedApp, TestCopyAtlasSideBarKeepsItsLayoutMode and TestCopyEveryAtlasLayoutKeepsEveryWidget (which compared every widget's key SET and so passed while the value was wrong) now compare the stored value for every Atlas_Core layout. Revert proof: with the builder, writer and describe changes reverted the new tests fail with the reported symptom. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…el (#1562) After `grant read *, write * on entity Shop.Customer to Shop.User;`, `diff-local` printed only "Summary: 0 new, 1 modified, 0 deleted" (mendixlabs#1630). The domain model renderer printed entities and attributes but not their access rules, so both sides rendered the same. Each entity is now followed by the grants DESCRIBE ENTITY prints (outputEntityAccessGrants), from a domain model decoded through the new backend method ParseDomainModelFromRaw. The decode goes through the codec because access-rule roles are stored as AllowedModuleRoles, not the SDK's ModuleRoles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
After `ALTER SETTINGS CONSTANT ... VALUE 'secret123' IN CONFIGURATION 'Default'` or `ALTER SETTINGS RUNTIME (BcryptCost: 11)`, diff-local printed "Summary: 0 new, 1 modified, 0 deleted" and `-f struct` said "(no changes)" (mendixlabs#1602). bsonToMDL had no case for the settings unit, so both sides got the same one-line generic header. The settings unit now renders with DESCRIBE SETTINGS's code (split out as writeProjectSettingsMDL), from a revision decoded by the new backend method ParseProjectSettingsFromRaw. Configuration constant values and the database password are masked with a per-process HMAC fingerprint, so a changed value still shows as a changed line without being printed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
A catalog SELECT removed the text `Catalog.` everywhere in the query, not only from the CATALOG.<table> prefix, so a module named Catalog could not be filtered on by qualified name: `'Catalog.Product' as lit` came back as 'Product', and `where QualifiedName = 'Catalog.Product'` returned 0 rows (mirror of mendixlabs#1553). Cause: execCatalogQuery stripped the prefix with a case-insensitive regex over the raw query text (`\bcatalog\.([a-z_][a-z0-9_]*)`), which cannot tell a table reference from data. It also rewrote quoted identifiers ("Catalog.x") and comments, and missed `CATALOG . ENTITIES` (the grammar reads CATALOG DOT name as three tokens, so whitespace at the dot parses and then failed with "no such table: CATALOG.ENTITIES"). The mode warning next to it made a second textual guess -- the word after the first "from " -- so a literal containing "from" hid the real table and only a join's first table was ever checked. Fix: rewriteCatalogTableRefs, a small scanner that lexes the query the way SQLite will: it skips single-quoted strings (doubled-quote escape), "..." / `...` / [...] identifiers and -- / /* */ comments, and drops `catalog` only when it is a whole identifier followed by a dot and a name (any case, whitespace or comments around the dot, not itself after a dot). It returns the tables it rewrote, and the mode warning now checks each of them. An ATTACHed `catalog` schema would avoid rewriting entirely, but the catalog is an in-memory SQLite database, which cannot be attached to itself without changing how it is opened; the scanner is contained and local. Every path that runs user SQL against the catalog goes through this one function: -c, exec scripts, the REPL and the LSP (which shells out to -c). Starlark lint rules get builtins, not raw SQL. Verification: - New tests: the rewrite table (literals, escapes, quoted identifiers, comments, whitespace at the dot, unterminated literal, plus controls: upper/lower/mixed prefix, joins, subqueries, ProductCatalog / my_catalog aliases, no prefix), the issue's queries end to end through the MDL parser on a catalog holding Catalog, ProductCatalog and MyCatalog modules, and the mode warning for a literal containing "from" and a gated joined table. - Revert proof: with the production change removed, 19 subtests fail with the reported symptom; the controls pass both ways. - Real 11.13.0 app with a Catalog module: before lit = "Product" and n = 0, after lit = "Catalog.Product" and n = 1, on -c, an exec script and the REPL; mdl-examples/bug-tests/catalog-1450-prefix-in-string-literals.mdl fails before ("no such table") and passes after. - go vet + go test ./mdl/executor/ pass; make check-findings passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream: mendixlabs#1621. Cause: the storage format had two sources. The reader decides v1/v2 from disk (an mprcontents/ folder beside the .mpr, reconciled by the Unit.Contents column) and reads units with that answer; every consumer that branches on the format (diff-local's guard, the mx harvest, diag --check-units, fix hashes) asks the reader. ProjectVersion.FormatVersion came separately from version.DetectFromDB, which read _MetaData._FormatVersion and, when the column was missing, assumed "a newer schema (11.6.2+), so 2". The column is missing precisely because the schema is v1 (absent in a 9.24.30 and an 11.13.0 v1 project; present and 2 in 11.6.6, 11.13.0 and 11.14.0 v2 ones), so every v1 project printed `MPR Format: v2` in SHOW VERSION and STATUS and logged mpr_format=2 in the session log that `diag --bundle` ships. Fix: DetectFromDB no longer sets FormatVersion (it reads the three columns both schemas share), and the reader stamps its own detection onto the ProjectVersion it returns — in OpenWithOptions after the Unit.Contents reconciliation, and in OpenWithDB. The MCP backend delegates to the same reader, so it is covered too. Verification: - modelsdk/mpr: TestProjectVersionReportsTheDetectedStorageFormat (v1 fixture, v2 control, v2 schema detached from its folder), TestOpenWithDBReportsTheFormatItWasGiven, TestDetectFromDBDoesNotGuessTheStorageFormat. - cmd/mxcli: TestShowVersionReportsTheStorageFormatOnDisk runs the real CLI on a v1 and a v2 project and asserts SHOW VERSION, STATUS and the session log's connect record. - Revert proof: with the production change removed, the v1 cases fail with FormatVersion = 2 / `MPR Format: v2` / mpr_format = 2 and the v2 controls pass. Reverting only the reader stamp fails every case with 0; moving the stamp before the reconciliation fails the detached-v2 case with 1. - Real apps (11.13.0, made with mx create-project, one --use-mpr-format-v1): v1 app v2 -> v1 in SHOW VERSION, STATUS and the session log; v2 app v2 before and after. diff-local, diag --check-units and fix hashes already treated the v1 app as v1 and are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its it does not render (#1512) A changed constant, a new module role, or any unit type without an MDL renderer was counted as modified with no hunk, because the generic renderer's header reads the same before and after (mendixlabs#1602, "at minimum, fall back to a field-level difference summary"). When both renderings agree but the stored documents differ, diff-local now walks the two documents and lists the changed fields by path, type and size, never by value, as an MDL comment hunk and as structural changes. Security$ModuleSecurity and Projects$ModuleSettings no longer fall into the module renderer (`create module ;`) through strings.Contains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
Run from outside the repository with `-p <app>/App.mpr`, diff-local failed with "failed to find changed files: failed to git diff: exit status 1" (side note in mendixlabs#1602); from a subdirectory of the repo it read working-tree files at repo-root-relative paths and counted nothing. Git now runs in the project's directory, reports `--relative` paths, and revisions are read as `<rev>:./<path>`, so the cwd no longer matters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
A page action calling a parameterless flow with an empty argument list, `Action: call microflow M.Ping()`, failed check with "mismatched input ')' expecting the start of a statement", while the flow body accepts `()` and the widget accepted the call without brackets (mendixlabs#1606). Cause: microflowArgsV3 in MDLPage.g4 required at least one argument. It is the argument rule of every page action (call microflow/nanoflow, show page and their MDL-DEPR020 spellings) and both flow data sources, so the same error hit Action, OnClick, OnChange, pluggable action properties, alter page set Action/DataSource, navigation and menu-document items, fragment arguments and building-block overrides. fragmentArgs had the same shape; there `use fragment Hdr()` was not even an error without a project: it parsed as two generic widgets (`use` named `fragment`, and `Hdr` with an empty property list), and check -p reported MDL-WIDGET25. Fix: both rules accept an empty list inside the brackets, as the flow body's callArgumentList and workflowCallArguments already do. No visitor change is needed: the builders return nil for no arguments, so `X()` builds exactly the statement `X` builds. Additive, so no mdl-version gate. describe still writes the bracket-less form. The page.action syntax topic and the create-page reference say so; the syntax-docs guard keeps the reference on the describe form with a corrected reason. Verification: - mdl/visitor/visitor_empty_call_args_test.go: 23 sites, X() vs X as whole statements and deprecation codes, a real argument list as the control. Reverting the grammar fails all 23 (22 parse errors, and use fragment on statement equality). - Real 11.13.0 app: a page written with () and its bracket-less twin store identical BSON once $ID and the page name are set aside, and describe identically without brackets; describe -> exec reports Unchanged page; mx check 0 errors. mdl-examples/bug-tests/widget-action-1516-empty-call-args.mdl. - All 81 non-.fail doctype-tests and all bug-tests check as before; only the new bug test changes (fail -> pass). Not changed on purpose: `use building block X()` (an override list) and `snippetcall (Params: ())` (a property map) stay errors with messages that name what is expected; a flow-body call still requires its (). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CE0129 "Administrator password has not been set" could only be resolved in Studio Pro (mendixlabs#624): `alter app security` had no property for it, and the backend no writer for Security$ProjectSecurity.AdminPassword. alter app security ( AdminPassword: 'N3w-Admin-Passw0rd' ); joins AdminUserName in the property list. '' is refused: measured on 11.13.0, an empty password is CE0129 at prototype and production level. mxbuild does not check it against the password policy, so neither does mxcli. The value is never echoed: exec reports "Admin password set", and `show project security` says only whether one is set. Verified on a copy of testdata/pedapp with the password blanked at production level: mx check 1003 errors incl. CE0129 before, 1002 and the same CE codes as the untouched app after. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
Five findings now share one defect: diff-local compares rendered MDL, so a change its renderer does not print counts as modified and shows nothing. The new page frames the shapes it has taken and the remedies, and points at the field-level fallback that closes the class. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
`create constant … type T default v` is MDL-DEPR136, which the conformance gate refuses in bug-test scripts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
It was not gofmt-clean on the base commit, so `make lint` failed there too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
On a page that shows the sign-in form, `playwright check` waited the whole --wait (33s at --wait 30s) and then reported the form as still loading, advising a longer --wait, next to the sign-in failure. The client keeps a POST /xas/ open behind the form (measured on 11.13.0 and 11.15.0), so the probe's "no request open" condition (#845) never held. Once the sign-in form is up the probe now settles on text and busy indicators alone, and the verdict does not call a sign-in form still loading. Against the same live apps: 33s -> 3s, still exit 1, with the sign-in form as the only failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
…gned in on (#1216) `mxcli playwright check http://frontend.local:8180/ -p app.mpr --role R` failed every run with "the sign-in form is showing, not the page", while the same command without the URL passed. With -p the base URL comes from the run handshake, http://localhost:<port>, and the sign-in ran there. The page named another host for the same app, the browser sent it none of localhost's cookies, and the client started anonymous. With a saved session the renewal path signed in on localhost again and retried, so each run also added one live session on the unlicensed runtime. The pages are now grouped by origin and each group signs in on its own host, with the session saved per host and user as before. Measured on 11.13.0 against the boot URL http://127.0.0.1:8180/ (the handshake says localhost). Before: FAIL, and three runs left three sessions (M2EE runtime_statistics). After: OK, and four runs left one. The check also tells the login where the runtime log is (<project>/.mxcli/runtime.log). The session-cap explanation can now fire. Before, it never could: at the cap, the login printed only "Sign in failed". Sign-out, best effort and never part of the verdict: - --fresh-login signs the replaced session out before signing in. - A session the run signed in that got no page past the sign-in form is signed out rather than kept. - The new --sign-out ends the run signed out. A session that is working is still kept and reused, so repeated checks hold one slot rather than signing in and out on each run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
`mxcli playwright check / /p/doesnotexist` printed the home page's title
and heading for both pages, then `OK 2 page(s)`. The probe already
recorded the location the browser ended on, but nothing compared it
with the URL asked for, and nothing printed it.
Measured on 11.13.0 and 11.15.0, with the same result on both:
- The runtime answers every /p/<x> with a 301 to /#/<x>, whether or not
a page has that URL.
- The client then replaces the location with /p/<x> for a known page.
For an unknown one it uses /, renders the home page and opens an
information dialog ("The page you requested was not found").
- The status is 200 throughout.
So the final path is the signal. It does not depend on the language,
and it needs no second load of the home page to compare titles.
ProbePages now records the URL each page was loaded from. When the
browser ended elsewhere, the verdict says where (`url=/`), and the
title and heading describe that page. A /p/ URL that did not stay put
fails, with one exception: a page that went to the sign-in form keeps
that failure as its only reason. Matching is exact, as the client's is:
/p/ITEMS and /p/items/ fail where /p/items passes. The client's
information dialog is shown as an ALERT line and does not fail a page.
`run --page-check` prints the same `url=` field.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
The options table gave --wait a 4s default; the code has used 15s since the probe began waiting for open requests (#845). Also say that the sign-in form is measured once it holds still rather than waited for. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
… is down (#866) startLocalPostgres fell back to the user-owned initdb cluster whenever no service manager made the port ready, without asking whether a system cluster for that port existed. Since the fallback works on Debian/Ubuntu, a container restarted with the system cluster down got a fresh, empty cluster on the same port, and the app booted healthy against it. Before initdb, probe the package-made data directories (postgresql-common via /etc/postgresql, RHEL/PGDG, Arch, Homebrew, Windows); a PG_VERSION that a non-root user may not stat counts as present. When one is configured for the requested port, refuse with its data directory and the command that starts it, unless the user-owned cluster already exists (a restart, noted) or MXCLI_ENSURE_DB_NEW_CLUSTER=1. Every initdb now prints a WARNING that a new, empty cluster was created. The bootstrap hook's banner takes mxcli's first "Error:" line, not the last line mentioning "error", which behind a service diagnostic was pg_ctlcluster's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
…stale Gradle daemon (#1340) mx sync-java-dependencies ran unbounded with no output, and every one-shot mx/mxbuild run used Gradle's default daemon, which outlives the run; with an idle daemon from an earlier run alive, the next sync hung for 10+ minutes printing nothing (mirror of mendixlabs#1483). One-shot runs (the sync, mxcli new's settle build, docker build) now get -Dorg.gradle.daemon=false appended to GRADLE_OPTS, keeping the user's options and LD_PRELOAD and any explicit daemon setting. The sync runs under the existing process-tree watchdog: "still resolving..." every 30s, killed after 10 minutes (MXCLI_SYNC_JAVA_DEPS_TIMEOUT) with an error naming the step, the likely cause and the last output. mxbuild --serve keeps its daemon. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
… stop reason (#1542) Every run --local process deferred an unconditional removal of .mxcli/run-local.json, including --setup, which the SessionStart hook runs on every session start, resume and compaction. So the hook deleted the handshake of the detached run serving the app, and oql/log fell back to default credentials against a live runtime: HTTP 403, blamed on the password (mirror of mendixlabs#1614). Separately, the stop reason was read from the JVM's stdout, but the trial licence's "Maximum run time exceeded" is an application log line that only reaches runtime.log, and run status printed only the first line of the recorded error. The handshake is now withdrawn only by the run whose pid it carries, right after run-state.json records phase stopped, ended and a one-line reason, read from the newest boot's section of runtime.log (licence limit, out of memory, else the last ERROR line). run status prints "stopped: trial licence time limit reached at 18:43:16 (runtime.log); restart with mxcli run restart -p ...", names the log's reason for a killed run, and flags a live run whose handshake is missing. oql, log and constant --apply say to check run status, not the credentials, when the handshake was missing or stale. The lifecycle is documented in the run-local skill and the docs-site page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
Five beats from the triage board's local-loop-silence fixes (#866, #1340, #1542, #1216, #998, and the sign-in form wait): a fallback whose success is the defect, a shared file needs an owner, a one-shot Gradle run must not leave or wait on a daemon, a signed-in check is a host and a session, and a settle rule written for one page holds every page to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
…ner property (#1698) The upgrade property test failed on mdl-examples/bug-tests/action-slot-not-an-action-1062.fail.mdl: the mdl 0 original of `container cCard (OnClick: TOTALLY_MADE_UP)` executes, and under `mdl 1;` the new per-widget verdict refused it - "`OnClick` is not a property mxcli writes on a container" (MDL-WIDGET52). A container's OnClick IS its click action. The visitor stores `OnClick:` under "Action" only when the value parses as an action (#603); a malformed value falls through to the generic `key: value` branch and keeps its key as written. That is the action slot holding something that is not an action, which MDL-WIDGET28 reports. Refusing it here as well named the wrong problem and, this rule being gated on the header and that one not, made the upgrade change what the script writes. Fix: nativeWidgetKeyAliases models the rename explicitly - `onclick` is accepted wherever the kind takes Action, and is owned by the click-action rules wherever Action is - without making it a builder read (TestNativeWidgetProps_AliasesFollowTheVisitor ties it to actionKeywordSource). It is the only key the visitor renames on a well-formed value: every other dedicated branch stores under its own name, and Visible/Editable lower to keys judged as one group. The same shape had a second hole: MDL-WIDGET28 looked its slots up by exact key, so the malformed value written `onClick:` (the casing the skills teach), `action:` or `onchange:` was reported by nothing and written as a dead control. On a built-in widget it now finds every case of the slot's name; on a pluggable widget only the exact one, since its keys are its package's own. Verification: TestNativeWidgetProps_MalformedActionIsTheActionSlotRules (no MDL-WIDGET52 for OnClick/onClick/action/onchange scalars, MDL-WIDGET28 for each, exec under mdl 1 builds the container) and _OnClickAliasControls (a well-formed OnClick is written, `Bogus:` on a container and a click action on a label are still refused). Revert proof: without the alias the first test fails with the reported refusal at check and at exec; with MDL-WIDGET28's exact lookup it fails to report four of the five. Upgrade property test, shards 1/3, 2/3, 3/3: pass (17 + 14 + 11 scripts execute to the same model, 62 executable). Re-sweep of all 1129 mdl-examples scripts including .fail ones: no MDL-WIDGET52 / MDL-V1-WIDGETPROP outside the two intentional .fail tests, which carry `mdl 1;` already. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(diff-local): show settings and access-rule changes, and never count a change silently
fix(lint): QUAL004 counts every catalog reference as a caller; published-service microflows get edges
fix(pages): refuse a property a built-in widget does not take; keep a scroll container's LayoutMode
fix(test): keep a call's own on error clause; the generated startup flow applies entity access
fix: a folder created mid-exec joins the cached hierarchy, so a grant finds the service in it
fix(grammar): an empty argument list on a page action or flow data source means no arguments
fix(catalog): rewrite the CATALOG. table prefix only where SQLite reads a table name
fix: SHOW VERSION reports the MPR format the reader detected, not a guess
`--ref main...feature-branch`, documented as "changes since common ancestor", warned "failed to read .feature version" for every unit and reported 0 modified: parseRefRange split on the first "..", so the target became ".feature". It also read the old side at main, where `git diff a...b` compares against the merge base. The range is now resolved once: three dots read the old side at `git merge-base a b`, labelled "merge base of a and b"; an empty side is HEAD, as it is to git. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
Git's rename detection reported a moved .mxunit as "R100 old new", which diff-local read as a modification of the old path; the new revision has no such file, so the unit was skipped with a warning and counted nowhere. A unit's file name is its ID, so the move is one unit deleted and one added: `git diff` now runs with --no-renames and reports it that way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
…n-in form The runtime answers a signed-in client's session request for a page its user roles may not open with 403, and the client lands on /login.html?messageCode=403#/<page>: the same sign-in form, with no message on it, that an anonymous browser or a forgotten session gets (401, no messageCode). The check took the form for "not signed in": it told the user to pass credentials, its stale-session retry signed in beside the live session on every run, and a check of only such pages signed its valid session out. PageSignals.AccessDenied() reads messageCode=403 from the final URL. Such a page now fails as "access denied: signed in as demo_user (user role User), the runtime refused /p/secret (403)", the verdict says ACCESS DENIED, and it no longer counts as needing a sign-in, so its session is neither renewed nor signed out. Measured on 11.13.0 and 11.15.0, `playwright check /p/secret /p/items -p app.mpr --role User` three times: before, `login demo_user` on every run and 1, 2, 3 live sessions (M2EE runtime_statistics); after, one sign-in and one session throughout, /p/secret alone included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
main had already fixed #1512 (af4c7de) and #1562 (3317b13) with the same design this branch used: Backend ParseProjectSettingsFromRaw / ParseDomainModelFromRaw, DESCRIBE's own writers, and a note for units whose renderings agree. Those are taken as on main, and this branch's duplicates are dropped: the HMAC value mask and settings renderer (cmd_diff_local_settings.go), the field-level fallback (cmd_diff_local_fields.go), the grant rendering, their tests, findings and bug-test scripts. Kept from this branch, re-applied on main's cmd_diff_local.go: git runs in the project directory with --relative paths (#1512's side note), --no-renames, the three-dot range read at the merge base, and the exact Projects$ModuleImpl dispatch. Their tests now use enumerations, whose values the rendering shows; main's git stub in the unrendered-change harness answers with project-relative paths, as git run in the project directory does. Generated backend stubs regenerated with both sides' methods (SetProjectAdminPassword from this branch). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
This reverts commit 79e6637. The file was already gofmt-clean: the gofmt on this container's PATH is an older Go's (/usr/local/go), not the go1.27.3 toolchain's that CI runs, and it formats this composite literal differently. CI's lint-go flagged the "fixed" version. Checked with $(go env GOROOT)/bin/gofmt: every tracked Go file is clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
fix: the local-loop-silence and project-security clusters, and the diff-local fixes #1745 did not cover
Ricovl
pushed a commit
to Ricovl/mxcli
that referenced
this pull request
Oct 28, 2026
…holder-dropped fix: a filter's Placeholder/Adjustable in create page are not written (ako#1652)
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.
Syncs
ako/mxcli:maininto upstream: 34 commits from fork PRs ako#1745–ako#1752 and ako#1755. Two of them are a gofmt and its revert, which net to nothing.Fixes #624, #1483, #1550, #1553, #1579, #1581, #1602, #1606, #1614, #1621, #1630, #1645, #1651 and #1659.
diff-local(#1602, #1630)diff-localreports the project-settings unit as modified but prints no difference #1602) or a grant on an entity (diff-local counts a domain model as modified after a grant, but prints no difference #1630) was counted as modified but printed no difference. Both now print their hunk.--ref a...bused to read every unit at.band diff nothing.run --localandmxcli test(#1483, #1614, #1550, #1645)mx sync-java-dependenciesran unbounded with no output, behind a daemon left over from an earlier run.run-local.jsonno longer vanishes under a live run (run --local: .mxcli/run-local.json disappears while the app is believed up (once after a trial-licence stop), and callers get no reason #1614). Everyrun --localprocess, including--setup, which the SessionStart hook runs, removed the detached run's handshake.run statusnow gives a stop reason.--ensure-dbno longer provisions an empty cluster while the system cluster is down.mxcli testfixes:on errorclause no longer stopsmxcli testat a parse error (mxcli test: a call with its ownon errorclause in a test block produces an unparsable test microflow ("mismatched input 'ON' expecting ';'") #1550).mxcli test --localno longer fails with CE0114 when the app's after-startup microflow applies entity access (mxcli test --local: the generatedMxTest.RegisterEndpointdoes not apply entity access, so a project whose after-startup microflow does cannot be tested (CE0114) #1645).playwright check/p/URL no longer passes as the home page.--waiton the sign-in form.--wait's default and the sign-in form.Pages (#1651, #1606, #1659)
Caption:passes check and exec and is silently not written (inputs takeLabel:); check has no "property this widget does not have" warning #1651). For example, a textbox'sCaption:passed check and exec and was silently not written, because inputs takeLabel:. AnOnClickwhose value is not an action isn't misreported as an unknown container property.Action: call microflow X()on a widget parses (Action: call microflow X()on a widget does not parse; the same call parses in a flow body #1606), as it does in a flow.LayoutMode(describe layoutdrops the scroll container'sLayoutModeandcreate layoutcannot write it: a describe-and-copy of Atlas_SideBar becomes a Headline layout (LayoutMode:silently ignored; check/exec/mx check pass) #1659).Security and REST (#624, #1581)
alter app security ( AdminPassword: 'N3w-Admin-Passw0rd' );grant access on published rest servicefinds a service created in a new folder (grant access on published rest servicereports "not found" for a service created withfolderearlier in the same script; check passes #1581). It used to report "not found".Lint, refs and catalog (#1579, #1553, #1621)
entry_point_prefixes.mxcli -cno longer strips "Catalog." inside string literals (mxcli -c: 'Catalog.' is stripped inside string literals #1553).SHOW VERSIONreports MPR v1 for an MPR v1 project (SHOW VERSIONreportsMPR Format: v2for an MPR v1 project #1621).Docs
local-loop-silencewiki page is synced with the cluster's new findings