Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
b8e6b2b
fix(mappings): refuse to rewrite a SOAP-sourced mapping instead of dr…
ako Sep 1, 2026
0de62aa
feat(microflow): @position on a flow parameter, and stop moving hand-…
claude Sep 1, 2026
9a421c5
docs(proposal): spec authorable message definitions
ako Sep 1, 2026
96f6903
Merge branch 'main' into fix/soap-mapping-guard-365
ako Sep 1, 2026
e1717ae
Merge pull request #369 from ako/fix/soap-mapping-guard-365
ako Sep 1, 2026
ad991d3
Merge remote-tracking branch 'origin/main' into pr370-merge
ako Sep 1, 2026
cb6ecba
Merge pull request #370 from ako/claude/mxcli-findings-nnl181
ako Sep 1, 2026
fb2faf6
Merge pull request #371 from ako/feat/spec-message-definitions
ako Sep 1, 2026
dc7007f
docs(proposal): add targeted ALTER, and the nesting measurement that …
ako Sep 1, 2026
ff825ce
fix(diff): render both sides through one describer, and say what is n…
claude Sep 1, 2026
7c2c9b1
docs(proposal): project brain, with the brief's assumptions verified
ako Sep 1, 2026
c45d068
docs(proposal): correct the audience and the documentation finding
ako Sep 1, 2026
4c59ea0
docs(proposal): link the documentation-preservation defect to its issue
ako Sep 1, 2026
01869c1
Merge branch 'main' into feat/spec-message-definitions
ako Sep 1, 2026
00da58b
Merge pull request #372 from ako/docs/proposal-project-brain
ako Sep 1, 2026
f084531
Merge pull request #373 from ako/claude/mxcli-findings-nnl181
ako Sep 1, 2026
7d1639a
Merge pull request #375 from ako/feat/spec-message-definitions
ako Sep 2, 2026
2624123
test: cover the image widget in the doctype mx check gate
claude Sep 2, 2026
c791fcf
docs(site): rewrite the layout reference against shipped behaviour
claude Sep 2, 2026
f120e91
Merge pull request #376 from ako/claude/mendix-default-styling-1fgvpm
ako Sep 2, 2026
992cccc
test(navigation): pin the fallback page's $Type in the other two writers
claude Aug 31, 2026
8ff351b
fix(check): resolve icon references in placeholders, snippets, layout…
claude Sep 1, 2026
9dc93b7
fix(check): resolve the user role in HOME PAGE ... FOR
claude Sep 1, 2026
5ffbce0
docs: correct the claim that mxbuild tolerates the wrong fallback-pag…
claude Sep 1, 2026
0486ba5
Merge pull request #374 from ako/claude/mxbuild-diagnostics-spike-emta6h
ako Sep 2, 2026
d40c999
fix(executor): a rewrite no longer deletes an unstated doc comment
ako Sep 2, 2026
a278f09
fix(executor): carry documentation on 5 more rewrite paths (#1018)
ako Sep 2, 2026
ba4f167
fix(executor): carry documentation on 7 more rewrite paths (#1018)
ako Sep 2, 2026
db7c615
feat(messagedefs): grammar, AST and visitor for message definition co…
ako Sep 2, 2026
3e036a1
fix(executor): carry documentation on 5 more paths; 18 of 29 verified
ako Sep 2, 2026
7e2cbe3
feat(messagedefs): storage — semantic type, codec writer, both engines
ako Sep 2, 2026
a2e07a7
fix(executor): finish the documentation carry — 22 of 29 covered
ako Sep 2, 2026
95e82f3
docs(findings): record what the full 29-doctype pass taught (#1018)
ako Sep 2, 2026
ac815cd
Merge remote-tracking branch 'origin/main' into fix/documentation-pre…
ako Sep 2, 2026
a3a9ea2
fix(executor): all 29 doctypes carried and covered (#1018)
ako Sep 2, 2026
7c5fc9c
build(deps): x/crypto v0.55.0 -> v0.56.0 for GO-2026-6354/6355
ako Sep 3, 2026
c187f2f
fix(messagedefs): three derivations corrected against a real Studio P…
ako Sep 3, 2026
c57589d
Merge pull request #378 from ako/fix/x-crypto-6354-6355
ako Sep 3, 2026
e09216c
Merge remote-tracking branch 'origin/main' into fix/documentation-pre…
ako Sep 3, 2026
b9d422e
Merge pull request #377 from ako/fix/documentation-preserved-on-rewrite
ako Sep 3, 2026
9d43352
feat(messagedefs): executor — create, alter, describe, show, drop
ako Sep 3, 2026
86b187b
docs(messagedefs): example, skill, site reference, syntax help, finding
ako Sep 3, 2026
b723a00
Merge branch 'main' into feat/message-definitions-272
ako Sep 3, 2026
0fd687a
docs(proposal): shard the project brain by module, home it at docs/br…
ako Sep 3, 2026
4a5d036
docs(proposal): tier 1 is no longer blocked — #1018 has landed
ako Sep 3, 2026
31c099f
fix(mappings): carry OriginalValue and the snippet's formatting throu…
ako Sep 3, 2026
a4b4a66
Merge pull request #382 from ako/docs/brain-sharding-and-location
ako Sep 3, 2026
87ce7af
test(messagedefs): skip the doctype example on the legacy engine
ako Sep 3, 2026
9c35e95
docs(proposal): restate the brain's CLI surface and skill against sha…
ako Sep 3, 2026
767bc71
feat(brain): project knowledge store, phase 1 (mxcli brain)
ako Sep 3, 2026
7a7c496
docs(proposal): translations is partial, and two open questions are s…
claude Aug 31, 2026
71bb4dd
feat(brain): requirements and slices, with progress derived from the …
ako Sep 3, 2026
c85c896
feat(bootstrap): ask for requirements at the interview, and record th…
ako Sep 3, 2026
99bd6a1
feat(catalog): index every translatable string, not five hand-picked …
claude Sep 3, 2026
8439944
fix(lint): QUAL005 stops folding an enumeration's values into one group
claude Sep 3, 2026
a90222c
Merge pull request #380 from ako/feat/message-definitions-272
ako Sep 3, 2026
c6b5fc2
fix(odata): type an external action's return value and its parameters
claude Sep 3, 2026
4e6674d
Merge pull request #381 from ako/claude/mxbuild-diagnostics-spike-emta6h
ako Sep 3, 2026
db865b5
Merge branch 'main' into fix/mapping-originalvalue-379
ako Sep 3, 2026
11b068d
Merge pull request #384 from ako/docs/brain-cli-surface-and-skill
ako Sep 3, 2026
25dd8ff
Merge pull request #383 from ako/fix/mapping-originalvalue-379
ako Sep 3, 2026
7847b8a
Merge pull request #385 from ako/feat/brain-phase-1
ako Sep 3, 2026
85c43f6
Merge branch 'main' into claude/banking-app-feedback-do04dy
claude Sep 3, 2026
afaf131
Merge pull request #386 from ako/claude/banking-app-feedback-do04dy
ako Sep 3, 2026
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
7 changes: 7 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"permissions": {
"allow": [
"Bash(bash /tmp/claude-1000/-workspaces-ako-mxcli/e4512e16-4485-4216-afba-df4212243089/scratchpad/verify-rebuild.sh 2>&1)"
]
}
}
2 changes: 2 additions & 0 deletions .claude/skills/fix-issue/findings/cmd-mxcli.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,5 @@
{"area": "cmd/mxcli", "date": "2026-08-31", "symptom": "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`", "cause": "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", "file": "`cmd/mxcli/tunnelhub/sessions_test.go` (`TestSessionLog_PersistAndPrune`), `cmd/mxcli/tunnelhub/sessions.go` (`load` → `pruneLocked` → `clock`)", "insight": "**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"}
{"area": "cmd/mxcli", "date": "2026-08-31", "symptom": "`mxcli test --local` cannot start a runtime for ANY project: `Error: local runtime: runtime admin API did not come up: runtime process exited during startup`, then `java.lang.IllegalArgumentException: Path '<project>/.mxcli/deployment-test/model/bundles' cannot be resolved in base path '<project>/.mxcli/deployment-test'`. The tree has `data/` and no `model/`", "cause": "**mxbuild writes the deployment to `<app dir>/deployment` and has no option to move it** \u2014 measured, not inferred: `--target=deploy` on a project whose `deployment/` had just been deleted recreated it there, `mxbuild --help` lists no deployment-path flag, and `BuildRequest` carries none. So giving the test boot a `DeployDir` of its own moved where the RUNTIME reads and not where the BUILD writes, and it booted against an empty directory. `StartLocalApp` now refuses a `DeployDir` the build will not populate, naming mxbuild as the constraint. The \u00a762 blanking the scratch tree was meant to prevent is fixed the only way the constraint allows: `preserveWebClientBundle` copies `deployment/web/dist` aside before the boot and puts it back after (a few MB of copy, against the ~30s re-bundle that made warning the earlier choice), restoring only when the bundle is actually gone so a fresher one is never clobbered.", "file": "`cmd/mxcli/docker/localapp.go` (`checkDeployDirIsBuildable`, the `preserveWebClientBundle` call), `cmd/mxcli/docker/webclient_preserve.go` (new), `cmd/mxcli/docker/localapp_integration_test.go` (new), `cmd/mxcli/testrunner/localapp_options.go`, `cmd/mxcli/testrunner/runner_local.go`, `cmd/mxcli/testrunner/runner.go`", "insight": "**The lesson is in the tests that did not catch it**, and two reporting projects drew it independently (mxcli-ledger \u00a7150, mxcli-sudoku \u00a751): four unit tests asserted `DeployDir` was set, was under `.mxcli/`, was per-project and was not the dev loop's \u2014 all four passed against a build that could not start, because every one was about the OPTION while the symptom lived in what is on disk after mxbuild runs. A fix that redirects a consumer without redirecting the producer moves the failure rather than removing it. The guard is now an integration test asserting the artefact: after a real build, the directory the runtime boots against holds `model/bundles`. Note the reporters' prescribed fix \u2014 thread `DeployDir` through the build \u2014 is not available; mxbuild has no such parameter, which is why the shared tree is accepted and the bundle carried across instead. Controls, both end-to-end on a real 11.13 project: the pre-fix binary reproduces the reported JVM error byte for byte while the fixed one passes; and with `preserveWebClientBundle` stubbed the sentinel bundle is destroyed by a test run that still reports all tests passed. Reinstating the regression fails the new integration test naming both missing paths."}
{"area": "cmd/mxcli", "date": "2026-09-01", "symptom": "After `mxcli test --local`, a live `mxcli run --local` serving the SAME project starts answering **HTTP 200 with a zero-byte body** on every microflow-backed resource \u2014 not a 500, not an error page \u2014 while source-backed ones keep working, so half the app looks fine. The runtime log shows `java.lang.NoClassDefFoundError` on a project class. In a two-app solution it surfaces as tests failing in the OTHER app.", "cause": "The test run recompiles the project's Java into `deployment/run/bin`, which is the classpath the running JVM is holding open. Measured on a real 11.13 project: after one test run all 134 class files have **new inodes and byte-identical content** \u2014 every one deleted and rewritten. A JVM loads classes lazily, so one it has not reached yet can fail permanently. mxcli cannot prevent this: mxbuild's Gradle pass owns the compile and the deployment directory cannot be moved (ledger \u00a7150). So it warns instead, which is what was missing.", "file": "`cmd/mxcli/devloop_recompile_warning.go` (new \u2014 `warnIfDevLoopServing`, `recompileWarning`), `cmd/mxcli/cmd_test_run.go`; reads the existing `cmd/mxcli/devloop_handshake.go`", "insight": "**The mechanism already existed and a duplicate would have broken it.** `mxcli run --local` publishes `devLoopHandshake` at `.mxcli/run-local.json` for `mxcli constant set --apply` \u2014 same path, same pid-liveness staleness check, plus the `adminPass` and `bootConfig` that `--apply` and `--attach` depend on. A second state file was written at that path before this was noticed; it parsed fine (JSON ignores unknown fields) but its WRITER would have silently dropped those two keys. Grep the path before inventing a file. **The liveness check is the feature**: a `run --local` killed or ended by its development licence (\u00a760, measured lifetimes under six hours) leaves the file behind, and a warning driven by the file alone fires forever \u2014 one that is always wrong teaches the reader to skip it. It **warns rather than refuses**, since the warm loop exists so an app can stay up while you work and the reporting project runs two apps that way; neither `--attach` nor `--skip-build` builds, so neither warns. The finding's cost was diagnosis, not breakage \u2014 108 log lines and a wrong hypothesis about a different app, for something whose remedy is one restart \u2014 so the warning names the symptom (HTTP 200, empty body), the part nobody guesses. Controls, end-to-end against a real `run --local`: the warning carries that app's actual pid and port and its handshake still has adminPass and 9 bootConfig keys afterwards; with the loop stopped, and with a stale dead-pid handshake, the same command is silent. Reported as mxcli-formula1 FINDINGS \u00a781."}
{"area": "cmd/mxcli", "date": "2026-09-03", "symptom": "`mxcli brain check` reports an entry as MISFILED even though the entry is correct and its anchor points at a real document — the anchor's target is simply of a document type the catalog's `objects` view does not index", "cause": "Misfiling was decided by comparing the shard against the modules of *resolved* anchors. An entry whose only anchor came back NotIndexable had an empty resolved-module list, so the comparison found no match and reported it misfiled — reintroducing, through the misfiling axis, exactly the false staleness that the NotIndexable state exists on the anchor axis to prevent", "file": "`cmd/mxcli/brain/entry.go` (`MisfiledIn`)", "insight": "When a check has two axes, an 'unknown' outcome on one of them must not be read as a negative on the other. The fix is to make misfiling *undecidable* rather than false when nothing resolved: with no resolved anchor there is no evidence about where the entry belongs, and an anchor that truly names nothing is already a failure on its own axis. Caught in development by a table test whose control stubbed the guard to `if false` — a control that deletes the block instead fails to compile on unused variables, which is not a control", "refs": ["ako/mxcli#385", "PROPOSAL_project_brain.md A1"]}
{"area": "cmd/mxcli", "date": "2026-09-03", "symptom": "`mxcli brain check` exits 1 on a requirement that is simply not built yet — the entry is correct and current, and the check reports its anchor as NOT FOUND", "cause": "Requirements were recorded as ordinary brain entries, but an entry's anchor was assumed to point BACKWARD at something that exists. A decision's unresolved anchor means the decision is stale; a requirement's unresolved anchor means the work is not done. Same syntax, opposite meaning, and the store had no way to tell them apart", "file": "`cmd/mxcli/brain/entry.go` (`Kind`), `cmd/mxcli/brain/check.go` (`checkSlice`)", "insight": "Before adding a record type to an existing store, ask what a FAILED validation means for it — not just what it looks like. Requirements and decisions share the anchor syntax exactly, which is what made them look like the same thing; they differ only in the direction the anchor points, and that difference is the whole lifecycle. Measured before designing: one unbuilt requirement filed as a decision took `brain check` to exit 1, which settled it in one command. The inversion then pays for itself — a requirement is 'built' when its anchors resolve, so `brain plan` reports progress derived from the model (measured 0/1 -> 1/0 after creating the microflow, with the plan file untouched) instead of a status column that goes stale silently", "refs": ["ako/mxcli#385"]}
2 changes: 1 addition & 1 deletion .claude/skills/fix-issue/findings/mdl-backend.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,4 @@
{"area": "mdl/backend", "date": "2026-08-26", "symptom": "`ALTER PAGE … SET Layout` / `ALTER LAYOUT` cannot find any widget in a layout — \"widget X not found\" for a widget DESCRIBE LAYOUT clearly shows", "cause": "Two finder gaps compounding. `findBsonWidget` starts from the page's `FormCall`, which a `Forms$Layout` does not have (its tree hangs off `Content`), so every widget in every layout was unreachable; and `findInWidgetChildren` never descended into a `ScrollContainer`'s five named slots, so a layout's topbar (`Top`) and navigation (`Left`) were out of reach even once the root was found — as was anything inside a scroll container a *page* places", "file": "`mdl/backend/pagemutator/mutator.go` (`findBsonWidgetInLayout`, region descent in `findInWidgetChildren`), `mdl/backend/pagemutator/scrollregion.go`", "insight": "**A region is addressed by slot, not by name** — it has no `Name`, so `INSERT INTO layoutContainer.top` reuses the dotted widgetRef that also serves DataGrid2 columns, and which one it means is decided by the named widget's `$Type`. Only `INSERT INTO` takes a region: BEFORE/AFTER position a widget among siblings, and silently treating them as INTO would put widgets somewhere the script did not ask for. The MDL slot name is `center`; the stored key is `CenterRegion`. Controlled by emptying the slot list and by respelling the centre key"}
{"area": "mdl/backend", "date": "2026-08-27", "symptom": "No export mapping mxcli writes matches its Studio Pro original, so every one stays in #260's silent-loss set even once its source kind is authorable", "cause": "The export writers hardcoded three properties the IMPORT twin already read off the element: `MinOccurs 0` (a schema root has **1**), `MaxLength 0`, and `IsKey` not written at all. `MaxLength` is the one that cannot be a constant — Studio Pro stores **0 for a string element and -1 for a numeric one**, mirroring the bound schema element exactly as `MaxOccurs` already did", "file": "`mdl/backend/modelsdk/mapping_write.go` (`exportValueElementToGen`, `exportObjectElementToGen`) + `mapping_read.go`, `sdk/mpr/writer_export_mapping.go`, `modelsdk/mpr/serialize_mappings.go`, `mdl/executor/cmd_export_mappings.go`, `model.ExportMappingElement`", "insight": "The export element model had **none** of these fields and the reader populated none of them, so this is four layers (model, reader, builder, three writers), not a writer patch — and a writer patch alone would have written zeros from an empty model. Clone them from the schema element where the builder already clones `MaxOccurs`. Check the import twin first when an export property looks wrong: this was a divergence between the two writers, not a considered decision, and the import side is the correct reference. Repro `mdl-examples/bug-tests/mapping-277-export-property-set.mdl`, tests `sdk/mpr/writer_export_mapping_properties_test.go`. Issue ako/mxcli#277", "refs": ["#260", "ako/mxcli#277"]}
{"area": "mdl/backend", "date": "2026-08-27", "symptom": "A rebuilt mapping drops `MessageDefinition2`, so a document written by Studio Pro 11.10+ never round-trips", "cause": "The key is version-introduced — `modelsdk/gen/mappings/version.go` records `messageDefinition2` as `Introduced: \"11.10.0\"` — and gen generates **no accessor** for it, so nothing read or wrote it. A blank 11.13 app's own mappings carry it as `\"\"`; none of the older pinned fixtures has it at all", "file": "`model.ImportMapping`/`ExportMapping` (`MessageDefinition2 *string`), `mdl/backend/modelsdk/mapping_read.go` (`messageDefinition2FromRaw`) + `mapping_write.go`, `sdk/mpr/parser_*_mapping.go` + `writer_*_mapping.go`, `mdl/executor/cmd_import_mappings.go` + `cmd_export_mappings.go`", "insight": "**Carry it, do not derive it.** A pointer, because nil (absent) is NOT the same as present-and-empty — writing the key onto a pre-11.10 document is the overlay-rule mistake CLAUDE.md warns about, which mxbuild tolerates and Studio Pro refuses to open. The executor decides: carry `existing.MessageDefinition2` on an update, apply the version gate only on a CREATE where there is nothing to read it off. A plain version gate in the writer looks equivalent and is not — it re-adds the key to every older document a rewrite touches, which turned four previously-clean fixtures red. gen having no accessor means the read goes to raw BSON, the route `parameterEntityFromRaw` takes. **`MappingSourceReference` is the same family and deliberately NOT carried**: its gate (10.16) predates every project in the field, and the codec emits it through a package-level `TypeDefaults` registration, so making it conditional would touch every mapping write to preserve one pre-10.16 fixture. Issue ako/mxcli#279", "refs": ["ako/mxcli#279"]}
{"area": "mdl/backend", "date": "2026-08-31", "symptom": "`DESCRIBE NAVIGATION` prints `home page` and the menu but **silently omits `login page` and `not found page`**, so pasting its output back (the documented copy workflow) deletes both from the profile. The clauses are on disk and `MXCLI_ENGINE=legacy` prints them", "cause": "The **reader**, not the writer: `mdl/backend/modelsdk/navigation_read.go` type-asserted only the `$Type`s `modelsdk/gen` declares for those two slots, and neither is what the documents carry — `LoginPageSettings` is stored as `Forms$FormSettings` with the page under `Form` (gen expects `Navigation$NavigationProfileLoginFormSettings` / `LoginPage`), and `NotFoundHomepage` as `Navigation$HomePage` (gen and `generated/metamodel` both expect `Navigation$NotFoundHomePage`). A failed type assertion leaves the field empty, so the loss is silent", "file": "`mdl/backend/modelsdk/navigation_read.go` (`navLoginPageOf`, `navNotFoundPageOf`), cross-check `generated/metamodel/types.go` `NavigationNavigationProfile`", "insight": "**The other engine is the control.** Legacy read the same bytes correctly throughout, which is what identifies a reader bug: `describe navigation X` on both engines must agree, and a disagreement localises the defect to the one that reads through gen. Accept the `$Type` the documents actually carry and keep gen's as a fallback branch. Note the two slots fail in **opposite directions** and want opposite fixes: for the login page a real Studio Pro document and `generated/metamodel` agree with the writers, so **gen** is wrong; for the not-found page — Studio Pro's **\"Fallback page\"** — metamodel and gen agree with each other and the three mxcli **writers** are the odd one out, emitting `Navigation$HomePage` where Studio Pro stores `Navigation$NotFoundHomePage`. Only a reference document could tell those apart, since mxbuild accepts either; ako/TestApp supplied it. Keep reading both `$Type`s regardless: documents written before the writer fix carry the `HomePage` spelling and must keep round-tripping. Repro `mdl-examples/bug-tests/navigation-describe-profile-pages.mdl`"}
{"area": "mdl/backend", "cause": "The **reader**, not the writer: `mdl/backend/modelsdk/navigation_read.go` type-asserted only the `$Type`s `modelsdk/gen` declares for those two slots, and neither is what the documents carry \u2014 `LoginPageSettings` is stored as `Forms$FormSettings` with the page under `Form` (gen expects `Navigation$NavigationProfileLoginFormSettings` / `LoginPage`), and `NotFoundHomepage` as `Navigation$HomePage` (gen and `generated/metamodel` both expect `Navigation$NotFoundHomePage`). A failed type assertion leaves the field empty, so the loss is silent", "date": "2026-09-01", "file": "`mdl/backend/modelsdk/navigation_read.go` (`navLoginPageOf`, `navNotFoundPageOf`), cross-check `generated/metamodel/types.go` `NavigationNavigationProfile`", "insight": "**The other engine is the control.** Legacy read the same bytes correctly throughout, which is what identifies a reader bug: `describe navigation X` on both engines must agree, and a disagreement localises the defect to the one that reads through gen. Accept the `$Type` the documents actually carry and keep gen's as a fallback branch. Note the two slots fail in **opposite directions** and want opposite fixes: for the login page a real Studio Pro document and `generated/metamodel` agree with the writers, so **gen** is wrong; for the not-found page \u2014 Studio Pro's **\"Fallback page\"** \u2014 metamodel and gen agree with each other and the three mxcli **writers** are the odd one out, emitting `Navigation$HomePage` where Studio Pro stores `Navigation$NotFoundHomePage`. ako/TestApp supplied the reference document that settled it. **Correction (2026-09-01): mxbuild does NOT accept either.** Measured on 11.13 against a build emitting the old spelling, `mx check` and `mxbuild --target=deploy` both exit 1 with \"Object of type 'Mendix.Modeler.WebUI.Navigation.HomePage' cannot be converted to type '...NotFoundHomePage'\" -- the project will not LOAD, so every downstream check is lost. What actually let it through is that nothing ever BUILT a project with a fallback page set: the automated mx-check coverage is doctype-tests/ only and no script there sets one, so the first was added by the fix itself. **Generalisable: 'the build tolerates it' is a claim that needs the same control as the fix** -- revert the writer, rebuild, and run the tool, or the reason a bug escaped gets recorded backwards and sends the next reader looking in the wrong place. Keep reading both `$Type`s regardless, but for the repair path rather than round-tripping: a pre-fix project does not build, and mxcli reads BSON directly, so accepting the old spelling is what lets it open and fix one. Repro `mdl-examples/bug-tests/navigation-describe-profile-pages.mdl`", "symptom": "`DESCRIBE NAVIGATION` prints `home page` and the menu but **silently omits `login page` and `not found page`**, so pasting its output back (the documented copy workflow) deletes both from the profile. The clauses are on disk and `MXCLI_ENGINE=legacy` prints them"}
Loading
Loading