Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .claude/skills/fix-issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -759,3 +759,4 @@ extracting `OffsetExpression`/`LimitExpression`.
| After `mxcli test … --local`, an app another `mxcli run --local` is serving goes blank while still answering HTTP 200 (~1.7 KB, the Mendix SPA shell); the runtime log shows `Connector: 404 - file not found for file: dist%2Findex.js` and `deployment/web/dist` is gone | `cmd/mxcli/testrunner/localapp_options.go`, `cmd/mxcli/testrunner/runner_local.go` (`localTestDeployDir`), `cmd/mxcli/testrunner/runner.go` (`checkScratchDeploymentExists`) | A local test run already used its own ports and its own `<project>_test` database — the code comment says why, verbatim — but shared the **deployment directory**, which is the one the *browser* reads. A headless test boot does not bundle the web client, so its build left the running app serving the shell over a 404: tests pass, run keeps running, app is blank, nothing reported at either end. **Detection was not the fix**: the two processes use different ports by design, so no port check can see it, and a lock file would only turn a silent blanking into a refusal. The test boot now builds into `<project>/.mxcli/deployment-test/` — gitignored, already where the test runtime log lives — which makes the collision impossible. Note booting a runtime against the shared directory damages it even **without** a rebuild (the packaging step removes the bundle — FINDINGS §35, `ReportLostWebClientBundle`), so "reuse the dev loop's tree read-only" is not an alternative. Consequence to wire: `--skip-build` used to mean "reuse deployment/" and now has nothing until tests have run once, so it is refused with the reason rather than failing inside the runtime boot against a path the user never chose. Reported as mxcli-formula1 FINDINGS §62 |
| A widget keyword the grammar accepts is absent from `mxcli syntax page widgets`, so it is concluded not to exist and worked around at length (reported for `tabcontainer`, which cost two days and five hand-rolled pages) | `cmd/mxcli/syntax/features_page.go`, `cmd/mxcli/syntax/widget_keywords_drift_test.go` | The lesson the reporter drew — "absence from the documentation is not absence from the grammar" — is true and is a bad thing for the docs to require. `TestEveryWidgetKeywordIsInAPageSyntaxTopic` makes it false instead: it reads the `widgetTypeV3` rule out of the **committed** `.g4` (only the *generated parser* is uncommitted, and the grammar is the authority the reporter was told to consult) and fails when a keyword appears in no `page.*` topic. It found **18**, not one. Exemptions go in `documentedElsewhere` **with the topic that owns them** — layout constructs (`scrollcontainer`, `region`, `navigationtree`, `menubar`, `placeholder`) and pluggable-widget object-list keywords (`group`, `series`, `marker`, …) are not page widgets; an entry with no home is the same defect. The guard carries its own vacuity control: a keyword that does not exist must not match, and one that does must. **Do not document a keyword without running it** — probing all 18 on 11.13 found four the parser accepts and the *default engine refuses* (`statictext`, `staticimage`, `dynamicimage`, `dropdown` → "widget *pages.X not yet supported by the modelsdk engine"), two refused on both engines (`referenceselector`, `legacydatagrid`), and one whose bare form emits **CE0463** (`image`). Reported as mxcli-formula1 FINDINGS §69 |
| Every open PR goes red at once on `build-and-test` with a failure in a package none of them touched — `--- FAIL: TestSessionLog_PersistAndPrune`, "after reload+prune: 0 records, want 1" — and the same test fails on a clean checkout of `main` | A **time bomb in the test**, not a regression: the fixture pinned `base := time.Date(2026, 8, 1, ...)` against a 30-day retention window, and `NewSessionLogFile` prunes inside `load()` — *before* the test can assign `log2.now`, so the reload prune runs on the real `time.Now()` whatever clock is injected afterwards. It passed for 30 days and then failed permanently, on every branch simultaneously | `cmd/mxcli/tunnelhub/sessions_test.go` (`TestSessionLog_PersistAndPrune`), `cmd/mxcli/tunnelhub/sessions.go` (`load` → `pruneLocked` → `clock`) | **First establish it is not yours**: run the failing test on a clean `origin/main`. Several PRs failing on one unrelated test is the signature. Then make the fixture relative — `base := time.Now().UTC()` — so the record ages, not the calendar, decide the outcome; the other tests in the file keep their fixed base legitimately, because they use `NewSessionLog` and inject the clock before recording. **A date fixture is only safe where no code path reads the real clock**; the moment a constructor prunes, expires or compares against `time.Now()` before the seam is in place, an absolute date has a fuse on it. Control the repair: stub `pruneLocked` to a no-op and confirm the test still fails (2 records, want 1), or the fix is just a test that stopped testing |
| Every page menu item in an **mxcli-authored navigation profile** loses the page's own title, and `mx check` reports one **CW0263 "Empty template"** warning per item while errors stay at 0 (16 of them on a real 11.12.3 app) | `Forms$FormSettings.TitleOverride` written as an **empty** `Microflows$TextTemplate` instead of `null` — the #812 defect above, in the three writers #812 did not touch. An empty template is an override to `""`, not the absence of one. Unlike the ShowPage/button paths there is nothing to preserve: `types.NavMenuItemSpec` has no title field, so MDL cannot author a navigation title override and the value is unconditionally null | `sdk/mpr/writer_navigation.go` (`buildFormSettingsBson`), `mdl/backend/modelsdk/navigation_write.go` (`navFormSettingsBson`), `modelsdk/mpr/nav_patch.go` (`navpBuildFormSettingsBson`) | Emit `{Key: "TitleOverride", Value: nil}` in all three. **Grep the builder's callers before concluding a navigation fix is menu-only** — each of the three is also the profile's **login page** builder (`writer_navigation.go:116`, `navigation_write.go:127`, `nav_patch.go:122`, plus `navigation_profile_add.go:108`), so one edit per engine covers both `Forms$FormAction` and `LoginPageSettings`, and a fix aimed only at menu items would have missed half the emitters. Verify against a **Studio Pro document already in the project**, not against the warning count: a blank app's own navigation unit stores `TitleOverride = null` on both the login settings and the home menu item. Read it with `f=$(grep -ral NavigationDocument app/mprcontents \| head -1)` — `grep -a` is required, a `.mxunit` is raw BSON and plain `grep -rl` skips it as binary — then `strings -a "$f" \| grep -c TextTemplate`: **4 before (3 page items + login page), 0 after**, with `grep -c TitleOverride` staying at 4 so the key is still written. Measured on 11.12.0 on both engines. These three paths are raw `bson.D` → `bson.Marshal` → `UpdateRawUnit`, so #812's second trap (a `codec.RegisterTypeDefaults` `NullFields` entry clobbered by another registration for the same `$Type`) cannot apply — which also means a shape assertion on the builder is the only unit-level guard there is. Repro `mdl-examples/bug-tests/989-navigation-title-override.mdl`. PR #989 |
153 changes: 153 additions & 0 deletions mdl-examples/bug-tests/989-navigation-title-override.mdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
-- PR #989: navigation page actions got an empty TitleOverride instead of null,
-- blanking the page title on every mxcli-authored menu item.
--
-- The same defect as #812, in the writers #812 did not touch. All three
-- navigation writers built their Forms$FormSettings with
--
-- TitleOverride: { $Type: "Microflows$TextTemplate", Text: {...}, Parameters: [] }
--
-- where Studio Pro writes `null`. An empty template is not the absence of an
-- override -- it IS an override, to the empty string -- so every page menu item
-- mxcli authored raised CW0263 "Empty template" and could render without the
-- page's own title.
--
-- Unlike the ShowPage / button paths there is nothing to preserve here:
-- types.NavMenuItemSpec has no title field, so MDL cannot author a navigation
-- title override at all and the value is unconditionally null.
--
-- The builder is shared with the profile's LOGIN PAGE (buildFormSettingsBson is
-- called for LoginPageSettings as well as for each menu item's Forms$FormAction),
-- so this script exercises both, plus a nested sub-menu -- sub-items are built by
-- the same recursive call.
--
-- THE REFERENCE IS IN THE PROJECT. A blank Mendix app's own navigation document
-- already contains both shapes, so the fix can be checked against a Studio
-- Pro-authored document rather than against a warning count. On a blank 11.12
-- app, before this script runs:
--
-- LoginPageSettings <Forms$FormSettings>
-- Form = ""
-- ParameterMappings [marker 2, 0 items]
-- TitleOverride = null <-- the shape mxcli must write
-- Menu.Items[0].Action.FormSettings <Forms$FormSettings>
-- Form = MyFirstModule.Home_Web
-- ParameterMappings [marker 2, 0 items]
-- TitleOverride = null
--
-- Verify without Studio Pro. `mxcli bson dump` has no navigation type, so read
-- the unit directly (MPR v2). Note `grep -a`: a .mxunit is raw BSON and plain
-- `grep -rl` skips it as binary.
--
-- mxcli exec 989-navigation-title-override.mdl -p app.mpr
-- f=$(grep -ral NavigationDocument app/mprcontents | head -1)
-- strings -a "$f" | grep -c TextTemplate
--
-- Measured on a real 11.12.0 v2 app, both engines (MXCLI_ENGINE=legacy selects
-- sdk/mpr/writer_navigation.go, the default selects
-- mdl/backend/modelsdk/navigation_write.go):
--
-- before the fix: 4 -- one per Forms$FormSettings: 3 page menu items + the
-- login page. This is the control: revert TitleOverride
-- to navEmptyTextTemplate() and the 4 come back.
-- after the fix: 0 -- while `strings -a "$f" | grep -c TitleOverride` stays
-- at 4, so the key is still written, now as null.
--
-- And at the layer the symptom was reported in:
--
-- mxcli docker check -p app.mpr
-- -> 0 errors before and after; CW0263 warnings drop by one per
-- Forms$FormSettings written. Measured on a real 11.12.3 app in the
-- PR: 199 -> 183.
--
-- Two things this script also makes visible, both OUT OF SCOPE for #989 and
-- neither introduced by it:
-- * `describe navigation Responsive` prints no `login page` line even though
-- the document carries Form = Issue989.NavLogin, so a describe -> exec
-- round-trip drops the login page. The reader type-asserts
-- *genNav.NavigationProfileLoginFormSettings (property `LoginPage`), and
-- both Studio Pro and mxcli store Forms$FormSettings (property `Form`).
-- * every list these writers emit carries typed-array marker 1 -- HomeItems,
-- ParameterMappings, PagesForSpecializations, Menu.Items, Caption.Items --
-- where the same blank app's own document has 2 or 3 for those fields.
-- Marker 1 is NOT invalid: Mendix writes it for by-name reference and string
-- lists (CustomWidgets$WidgetValueType.AllowedTypes, 212k occurrences in a
-- Marketplace package mxcli has never touched), so this is a per-field
-- mismatch rather than corruption. Fixed separately.


create module Issue989;
create module role Issue989.User;

-- Distinct titles, so a blanked one is visible rather than merely absent.
create page Issue989.NavHome (
title: 'Home Page Title',
Layout: Atlas_Core.Atlas_Default
)
{
container c1 { }
}
/

create page Issue989.NavReports (
title: 'Reports Page Title',
Layout: Atlas_Core.Atlas_Default
)
{
container c1 { }
}
/

create page Issue989.NavSettings (
title: 'Settings Page Title',
Layout: Atlas_Core.Atlas_Default
)
{
container c1 { }
}
/

create page Issue989.NavLogin (
title: 'Sign In Page Title',
Layout: Atlas_Core.Atlas_Default
)
{
container c1 { }
}
/

-- Three page menu items (one of them nested, to cover the recursive sub-item
-- build) and a login page: four Forms$FormSettings, four TitleOverrides that
-- must all be null.
create or replace navigation Responsive
home page Issue989.NavHome
login page Issue989.NavLogin
menu (
menu item 'Home' page Issue989.NavHome;
menu 'Admin' (
menu item 'Reports' page Issue989.NavReports;
menu item 'Settings' page Issue989.NavSettings;
);
);

-- A microflow action and a sub-menu container write Forms$MicroflowAction /
-- Forms$NoAction, which carry no FormSettings -- included so the TextTemplate
-- count above is attributable to the page items alone.
create microflow Issue989.DoNothing ()
begin
return;
end;
/

create or replace navigation Responsive
home page Issue989.NavHome
login page Issue989.NavLogin
menu (
menu item 'Home' page Issue989.NavHome;
menu item 'Run' microflow Issue989.DoNothing;
menu 'Admin' (
menu item 'Reports' page Issue989.NavReports;
menu item 'Settings' page Issue989.NavSettings;
);
);

describe navigation Responsive;
Loading