fix(pages): write a null TitleOverride, unblanking every popup caption (#812) - #68
Merged
Conversation
mendixlabs#812) Every Forms$FormSettings / Forms$PageSettings mxcli wrote carried an empty Microflows$TextTemplate as its TitleOverride, 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 popup opened by an mxcli-authored button or Show Page action rendered with a blank caption and just the close button. The reporter found 10 broken popups (all mxcli-authored) against 58 correct ones in the same project. The same unconditional write hid a second defect: an override the author did ask for, `show page M.P with title = 'X'`, was discarded. The syntax parses, the visitor sets ast.ShowPageStmt.Title and the builder sets ShowPageAction.OverridePageTitle — but no writer ever read that field. Before this change `grep -rn OverridePageTitle` matched exactly two lines: the struct field and its assignment. Both halves now round-trip. Two traps made this hard to see, and both are recorded in the symptom table. The "must be non-nil" comments cited issue mendixlabs#295 as justification. mendixlabs#295 was about Forms$PageVariable on a PageParameterMapping — a different field — and the conclusion was generalised to TitleOverride without ever being tested. It is false: with the null in place, against Mendix 11.6.6, mxcli docker check -> "The app contains: 0 errors." mxcli docker build -> "Build complete." so the loader accepts it, which is precisely what the old comments said it would not. This repo's own .claude/skills/debug-bson.md already documented `{Key: "TitleOverride", Value: nil}` as the correct Forms$FormSettings shape. Two tests asserted the incorrect behaviour and have been inverted, with the reasoning recorded so the reversal is not silently re-reverted. codec.RegisterTypeDefaults OVERWRITES rather than merges, and Forms$FormSettings was registered twice — in microflow_write.go and widget_write.go. Registrations resolve by init order, so the NullFields entry added beside the microflow writer was clobbered and the null never reached the output. Consolidated to a single registration, with a comment at the surviving site. Scope: the microflow Show Page and widget-action paths, where the evidence is. Navigation writes the same empty template but the reported evidence is about popups, so it is left alone rather than changed on a guess. Verified end-to-end against a real project, not just in unit tests: show page P; -> TitleOverride: null show page P with title = 'X'; -> Microflows$TextTemplate containing 'X' actionbutton (action: show_page P) -> TitleOverride: null plus the mx check and MxBuild runs above. Reverting the fix makes the new tests fail with exactly the BSON shape quoted in the issue. Repro script in mdl-examples/bug-tests/. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012XR649rKk68z6gBpngu6MA
ako
force-pushed
the
claude/showpage-titleoverride-812
branch
from
August 1, 2026 03:13
a26130b to
361c53e
Compare
Resolves the recurring conflict in .claude/skills/fix-issue.md: every fix appends a symptom row at the same anchor, so any two branches that both add one collide. Both sides kept — this branch's mendixlabs#812 row plus the two loop rows that arrived from #63. Main has since gained #64 (runUpdateWidgets) and #66 (mandatory microflow semicolons). Parser regenerated against the new grammar; full suite green, and the example corpus is unchanged at 235/39 including this branch's repro script.
ako
pushed a commit
that referenced
this pull request
Aug 1, 2026
Same recurring conflict as #68: .claude/skills/fix-issue.md, where every fix appends a symptom row at the identical anchor. Both sides kept. check.go auto-merged cleanly — #64's runUpdateWidgets and this branch's localMxForVersion touch different functions. Parser regenerated against #66's grammar; full suite green.
ako
pushed a commit
that referenced
this pull request
Aug 1, 2026
Every bug fix touches .claude/skills/fix-issue.md, and new rows went in directly under the table header. Two branches fixing unrelated bugs therefore inserted at the same line, which git cannot merge — a conflict by construction rather than by bad luck. It cost five separate resolution rounds in one week (#59-#62 three times, then #68 and #69), and each round risks silently dropping a row: one earlier round was "resolved" by deleting a PR's rows entirely and restoring them in a follow-up. Appending puts each branch's insert at a different offset, which git merges without help. The table is unordered — it is looked up by matching a symptom, not read top to bottom — so position carries no meaning and appending costs nothing. Recorded in both places a contributor might look: the skill's How to Use, with the reasoning so it is not "fixed" back, and the PR checklist item in CLAUDE.md. Existing rows are deliberately left where they are. Reordering them would conflict with every open branch at once, which is the problem this change exists to avoid. Folded into this branch rather than opened separately: it edits the same How to Use block, so a sixth branch would have manufactured exactly the conflict it is meant to prevent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012XR649rKk68z6gBpngu6MA
ako
pushed a commit
that referenced
this pull request
Aug 1, 2026
#68 landed, putting its symptom row at the top of the table — the same line this branch inserts at, so the conflict recurred immediately after the previous resolution. That is the pattern, not bad luck. Resolved by keeping main's rows and moving this branch's row to the END of the table, which is the convention #70 introduces. Applying it here rather than waiting: this branch is the exact case it exists for.
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.
Fixes mendixlabs#812.
The bug
Every
Forms$FormSettings/Forms$PageSettingsmxcli wrote carried an emptyMicroflows$TextTemplateas itsTitleOverride, where Studio Pro writesnull.An empty template is not the absence of an override — it is an override, to the empty string. So every popup opened by an mxcli-authored button or Show Page action rendered with a blank caption and just the
×. The reporter found 10 broken popups (all mxcli-authored) against 58 correct ones from Studio Pro / marketplace modules in the same project.Reproduced and verified in a browser
A scratch Mendix 11.12.2 project, a popup page titled
Order Details Popup, and an mxcli-authored button that opens it. Same app, same page, booted viamxcli run --local; the only variable is which build wrote the page. Driven with Playwright, reading the caption out of the modal header:TitleOverridein BSONheaderTextnull"×\nOrder Details Popup""Order Details Popup"Microflows$TextTemplate"×"""— blankThat is the reported symptom reproduced exactly, and closed.
The build-level claim behind the original workaround is also disproved. The old comments said Studio Pro rejects a null embedded object on load. With the null in place, on 11.12.2:
A second defect the first one hid
The same unconditional write discarded an override the author did ask for.
show page M.P with title = 'X'parses, the visitor setsast.ShowPageStmt.Title, the builder setsShowPageAction.OverridePageTitle— and no writer ever read that field. Before this change,grep -rn OverridePageTitlematched exactly two lines: the struct field and its assignment.Both cases produced identical BSON, which is precisely why nobody noticed the second half. Both now round-trip.
Two traps, both now in the symptom table
1. A comment citing the wrong issue. The
must be non-nilcomments justified themselves with issue mendixlabs#295, which was aboutForms$PageVariableon aPageParameterMapping— a different field. The conclusion was generalised toTitleOverridewithout being tested, and the runs above show it is false. This repo's own.claude/skills/debug-bson.mdalready documented{Key: "TitleOverride", Value: nil}as the correct shape.Two existing tests asserted the incorrect behaviour. They are inverted here, with the reasoning recorded inline so the reversal is not silently re-reverted by someone reading the old comment.
2.
codec.RegisterTypeDefaultsoverwrites rather than merges.Forms$FormSettingswas registered twice — inmicroflow_write.goandwidget_write.go. Registrations resolve by init order, so theNullFieldsentry I added beside the microflow writer was clobbered and the null never reached the output. Caught only by dumping the BSON rather than trusting the passing test. Consolidated to a single registration, with a comment at the surviving site.Scope
The microflow Show Page and widget-action paths, where the evidence is. Navigation writes the same empty template at three sites and is deliberately left alone — the reported evidence is about popups, and changing navigation on an analogy is exactly the mistake that caused this bug in the first place.
Unit-level coverage
Reverting the fix makes the new tests fail with exactly the BSON shape quoted in the issue. Repro script added at
mdl-examples/bug-tests/812-showpage-title-override.mdl. Full Go suite green.🤖 Generated with Claude Code
https://claude.ai/code/session_012XR649rKk68z6gBpngu6MA