diff --git a/CHANGELOG.md b/CHANGELOG.md index e876905..30ebae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ three commits past it), and a bug report can name a release instead of a sha nob Sections dated before 2026-09-19 predate the cycle and stay as they are. ## Unreleased +- learn(skills/learned-file-upload-widget.md): **a file upload mxcli can author, with proof that it uploads.** The Mendix File Uploader 2.5.0 bound to a `System.FileDocument` specialisation: the MDL shape (entities, grants, create/delete microflows, advanced formats), which upload widgets mxcli cannot author (classic FileManager, PDS uploader), the two traps with workarounds (a simple-mode `allowedfileformat` passes exec and fails `mx check` with CE0463; an uploader DESCRIBE will not re-exec, `exposes 2 datasources`), and the six-step upload instrument. Field run on stock v0.24.0: the section-4 MDL taken verbatim from the skill gave `mx check` 0 errors, 2/2 files stored, 2/2 downloads sha256-equal, `.csv` rejected with 0 rows; both traps reproduce unchanged on v0.24.0 — a Mendix app-rebuild project - new(skills/mendix-best-practices-index.md): **one row per Mendix best-practice area: the Mendix docs page, the bundled `assess-quality` section, the toolkit skill that applies it before the write, and the `mxcli lint` rule that catches it after exec.** An index, not a copy — the practice text stays on the Mendix pages (17 URLs verified HTTP 200 on 2026-09-25) and in the mxcli-bundled skill; Mendix's own Best Practice Recommender rules (MXP001–016) anchor the performance rows, and four rows say out loud that no lint rule exists and the preflight checklist is the only check. Routed `all` agents, stages 3/5/6, group reference — Maurits Visser - learn(skills/microflow-preflight.md, agents/mdl-agent.md): **a microflow now gets a tier before any MDL — Simple, Guided or Split-first — and Split-first means a posted split plan (thin orchestrator + one `SUB_` per responsibility, with signatures) that the user confirms first.** Prompted by a colleague's session refusing a long microflow as "too difficult" while the same task went through on a stronger model: the piece was too big, not the task. mdl-agent gains two rules — never hand back "too difficult", hand back the split plan; escalate one failing `SUB_` by name after one retry, never the whole script. Also records the mxcli team's answer on positioning: a standalone `mxcli layout` command — which on v0.24.0 and upstream main (2026-09-25) arranges domain models only (`--dry-run` on a scratch copy of a PoC model: 10 entity moves, no microflow), so the no-`@position` rule and the if-branch workaround stand until a microflow mode ships; noted in the bug ledger and `learned-microflow-patterns.md` — Maurits Visser - learn(bug-logs): **`BUG-DRAFT-layout-merge-in-if-branch`** — the v0.24.0 layout engine (upstream #1154) puts the merge node on top of the activity that follows a loop inside an `if` branch, so `mxcli lint` reports MPR008 on a correct script that carries no `@position`; plain if/else and a branch holding only the loop lay out clean. Paste-ready draft in `bug-logs/pending-github-issues/`, NOT YET FILED. Matters to the lint ratchet (#134): an MPR008 whose two elements are a merge and the activity after a loop in an `if` branch is this bug, fixed by the workaround, never by `--update-baseline`. Measured on mxcli v0.24.0, Mendix 11.12.1, scratch copy of a PoC model — Maurits Visser diff --git a/README.md b/README.md index 3d1e7ac..35d27d6 100644 --- a/README.md +++ b/README.md @@ -623,6 +623,7 @@ Every mxcli project has a `.ai-context/skills/` directory (bundled by `mxcli ini | Generating a whole page tree in one script — the structure patterns that survive it | `skills/oneshot-page-structure-patterns.md` | | Building or auditing a collapsible sidebar nav — Atlas Core's collapsed state needs icons assigned per menu item or it silently clips label text | `skills/learned-sidebar-collapse-icons.md` | | Building or altering any data grid — native DATAGRID vs pluggable DG2 decision rule, the ALTER PAGE INSERT corruption, sort-by and filter-binding traps | `skills/learned-dg2-patterns.md` | +| Putting any file upload / attachment / document field on a page, an uploader page failing mx check with CE0463, or an uploader DESCRIBE that will not re-execute — the File Uploader MDL shape proven end to end on v0.23 and v0.24, the widgets mxcli cannot author, and the upload instrument | `skills/learned-file-upload-widget.md` | **Build · Agents — Mendix AI agents, tools, knowledge bases, chat UI** diff --git a/ROUTING.md b/ROUTING.md index 8452929..8ff018e 100644 --- a/ROUTING.md +++ b/ROUTING.md @@ -168,6 +168,7 @@ picks the row up. That is the whole procedure — there is no second list to rem | Generating a whole page tree in one script — the structure patterns that survive it | `skills/oneshot-page-structure-patterns.md` | mdl | 5 | ondemand | | Building or auditing a collapsible sidebar nav — Atlas Core's collapsed state needs icons assigned per menu item or it silently clips label text | `skills/learned-sidebar-collapse-icons.md` | mdl | 5 | ondemand | | Building or altering any data grid — native DATAGRID vs pluggable DG2 decision rule, the ALTER PAGE INSERT corruption, sort-by and filter-binding traps | `skills/learned-dg2-patterns.md` | mdl | 5 | ondemand | +| Putting any file upload / attachment / document field on a page, an uploader page failing mx check with CE0463, or an uploader DESCRIBE that will not re-execute — the File Uploader MDL shape proven end to end on v0.23 and v0.24, the widgets mxcli cannot author, and the upload instrument | `skills/learned-file-upload-widget.md` | mdl,test | 5 | ondemand | #### Build · Agents — Mendix AI agents, tools, knowledge bases, chat UI diff --git a/agents/mdl-agent.md b/agents/mdl-agent.md index 208b63d..abcc840 100644 --- a/agents/mdl-agent.md +++ b/agents/mdl-agent.md @@ -103,6 +103,7 @@ a rule below names an asset (e.g. "the wireframe", "the brief"), it means the pa | `skills/field-run.md` | Driving the whole toolkit pipeline on a real source to find what the written skills don't say — the toolkit is the subject, not the app it builds | | `skills/learned-mdl-cannot-express.md` | Before a wireframe or a design commits to a WIDGET — and when a page script hits a parse error that looks like a syntax mistake: the short list of things MDL cannot write at all, and the four-minute probe that answers it at Stage 3 instead of at build time | | `skills/learned-dg2-patterns.md` | Building or altering any data grid — native DATAGRID vs pluggable DG2 decision rule, the ALTER PAGE INSERT corruption, sort-by and filter-binding traps | +| `skills/learned-file-upload-widget.md` | Putting any file upload / attachment / document field on a page, an uploader page failing mx check with CE0463, or an uploader DESCRIBE that will not re-execute — the File Uploader MDL shape proven end to end on v0.23 and v0.24, the widgets mxcli cannot author, and the upload instrument | | `skills/scriptable-sp-verification.md` | Needing Studio Pro load evidence without a human at the GUI — direct-binary launch and log capture; a capture technique, NOT a validated pass/fail oracle | | `skills/learned-local-db-confusion.md` | A runtime test reads/writes data that then is not there, or vice versa — three local Postgres instances can answer on this box; resolve the real port from the project's own compose file first | | `skills/walking-skeleton.md` | Stage 5 start, before the first module of any entry mode — one entity, flow, page, nav, demo user, journey and screenshot proven in the running app, so build/run/look/test are known to work before a module depends on them | diff --git a/agents/test-agent.md b/agents/test-agent.md index 30eedbb..9120497 100644 --- a/agents/test-agent.md +++ b/agents/test-agent.md @@ -65,6 +65,7 @@ and `"DESCRIBE ..."` reads are always fine, and are how you ground every name yo | `skills/empty-widget-triage.md` | A page/grid/combobox renders empty (blank cells, zero rows, zero options) during UI review or an e2e run — before assuming a single cause | | `skills/doctor-triage.md` | doctor.sh reports FAIL or WARN, or someone asks whether a red setup line blocks them — check what is actually on the machine before naming a fix; a wrong-arch binary, a missing one and a broken self-check all read the same | | `skills/field-run.md` | Driving the whole toolkit pipeline on a real source to find what the written skills don't say — the toolkit is the subject, not the app it builds | +| `skills/learned-file-upload-widget.md` | Putting any file upload / attachment / document field on a page, an uploader page failing mx check with CE0463, or an uploader DESCRIBE that will not re-execute — the File Uploader MDL shape proven end to end on v0.23 and v0.24, the widgets mxcli cannot author, and the upload instrument | | `skills/learned-local-db-confusion.md` | A runtime test reads/writes data that then is not there, or vice versa — three local Postgres instances can answer on this box; resolve the real port from the project's own compose file first | | `skills/full-harness-audit.md` | The user asks for a full end-to-end test, a click-through proof, or does-everything-actually-work — or you are unsure which harness skill applies; this one routes you | | `skills/test-result-audit.md` | End of any build+test cycle that wrote docs/report.json — did the testing itself hold up, not just get filed; one level up from finding-disposition | diff --git a/bin/gate-check.sh b/bin/gate-check.sh index 5e24d45..4ac3734 100755 --- a/bin/gate-check.sh +++ b/bin/gate-check.sh @@ -1609,7 +1609,7 @@ stage_protocol_paths() { 2) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-brd.md skills/checkpoints/checkpoint-architecture.md skills/image-transcription.md skills/small-project-tier.md skills/kb-generation.md skills/brd-generation.md skills/brd-validation.md" ;; 3) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-design.md skills/small-project-tier.md skills/mendix-best-practices-index.md skills/layering-review.md skills/architecture-blueprint.md skills/modularize-domain.md skills/design-artifacts.md skills/brd-to-build-plan.md skills/workflow-structure-rules.md skills/learned-mdl-cannot-express.md" ;; 4) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-build.md skills/agent-roles.md skills/small-project-tier.md skills/module-brief.md skills/module-folder-convention.md skills/brd-to-build-plan.md skills/coverage-ledger.md skills/workflow-structure-rules.md skills/rest-integration-first-time-right.md skills/learned-constants-and-secrets.md" ;; - 5|build-ready) echo "skills/interview-protocol.md skills/grill-mode.md skills/agent-roles.md skills/module-brief.md skills/learned-mdl-preflight.md skills/module-folder-convention.md skills/learned-microflow-patterns.md skills/microflow-preflight.md skills/mendix-best-practices-index.md skills/ui-preflight-pages.md skills/design-spacing.md skills/learned-stylegallery.md skills/ui-loop.md skills/learned-mcp-patterns.md skills/module-review.md skills/testing-shape.md skills/microflow-loop-antipatterns.md skills/iterative-build-loop.md skills/mdl-cookbook-microflows.md skills/build/mdl/oneshot-mdl-method.md skills/learned-page-patterns.md skills/oneshot-page-structure-patterns.md skills/mendix-agents.md skills/mendix-agent-ui.md skills/mendix-agent-setup.md skills/fixture-seeding.md skills/journey-proof.md skills/monkey-test.md skills/report-schema.md skills/harness-architecture.md skills/process-coherence-pass.md skills/lint-that-actually-runs.md skills/improvement-register.md skills/journey-examples.md skills/wiring-sweep.md skills/learned-workflow-patterns.md skills/workflow-structure-rules.md skills/rest-integration-first-time-right.md skills/bug-submission-checklist.md skills/empty-widget-triage.md skills/learned-sidebar-collapse-icons.md skills/learned-popup-navigation.md skills/learned-datagrid-customcontent-binding.md skills/learned-popup-feedback-pattern.md skills/learned-mdl-cannot-express.md skills/learned-css-that-never-applied.md skills/learned-detection-gaps.md skills/learned-dg2-patterns.md skills/security-is-not-a-later-script.md skills/learned-local-db-confusion.md skills/full-harness-audit.md skills/test-result-audit.md skills/finding-disposition.md skills/preview-over-hub-tunnel.md skills/walking-skeleton.md skills/platform-link.md skills/teamserver-alignment.md skills/learned-constants-and-secrets.md" ;; + 5|build-ready) echo "skills/interview-protocol.md skills/grill-mode.md skills/agent-roles.md skills/module-brief.md skills/learned-mdl-preflight.md skills/module-folder-convention.md skills/learned-microflow-patterns.md skills/microflow-preflight.md skills/mendix-best-practices-index.md skills/ui-preflight-pages.md skills/design-spacing.md skills/learned-stylegallery.md skills/ui-loop.md skills/learned-mcp-patterns.md skills/module-review.md skills/testing-shape.md skills/microflow-loop-antipatterns.md skills/iterative-build-loop.md skills/mdl-cookbook-microflows.md skills/build/mdl/oneshot-mdl-method.md skills/learned-page-patterns.md skills/oneshot-page-structure-patterns.md skills/mendix-agents.md skills/mendix-agent-ui.md skills/mendix-agent-setup.md skills/fixture-seeding.md skills/journey-proof.md skills/monkey-test.md skills/report-schema.md skills/harness-architecture.md skills/process-coherence-pass.md skills/lint-that-actually-runs.md skills/improvement-register.md skills/journey-examples.md skills/wiring-sweep.md skills/learned-workflow-patterns.md skills/workflow-structure-rules.md skills/rest-integration-first-time-right.md skills/bug-submission-checklist.md skills/empty-widget-triage.md skills/learned-sidebar-collapse-icons.md skills/learned-popup-navigation.md skills/learned-datagrid-customcontent-binding.md skills/learned-popup-feedback-pattern.md skills/learned-mdl-cannot-express.md skills/learned-css-that-never-applied.md skills/learned-detection-gaps.md skills/learned-dg2-patterns.md skills/learned-file-upload-widget.md skills/security-is-not-a-later-script.md skills/learned-local-db-confusion.md skills/full-harness-audit.md skills/test-result-audit.md skills/finding-disposition.md skills/preview-over-hub-tunnel.md skills/walking-skeleton.md skills/platform-link.md skills/teamserver-alignment.md skills/learned-constants-and-secrets.md" ;; 6) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-cutover.md skills/mendix-best-practices-index.md skills/module-review.md skills/testing-shape.md skills/existing-app-assurance.md skills/app-analysis.md skills/module-dependency-review.md skills/microflow-loop-antipatterns.md skills/qa-loop-goal-pattern.md skills/mendix-agent-setup.md skills/e2e-harness-base.md skills/learned-db-assertions.md skills/fixture-seeding.md skills/journey-proof.md skills/monkey-test.md skills/learned-skill-ux-audit.md skills/learned-skill-scope-delta.md skills/report-schema.md skills/harness-architecture.md skills/process-coherence-pass.md skills/e2e-evidence-report.md skills/record-demo-video.md skills/share-demo-package.md skills/lint-that-actually-runs.md skills/improvement-register.md skills/journey-examples.md skills/wiring-sweep.md skills/workflow-structure-rules.md skills/bug-submission-checklist.md skills/empty-widget-triage.md skills/anonymize-client-app-for-demo.md skills/learned-css-that-never-applied.md skills/learned-detection-gaps.md skills/learned-local-db-confusion.md skills/full-harness-audit.md skills/test-result-audit.md skills/finding-disposition.md skills/handoff-to-studio-pro.md skills/preview-over-hub-tunnel.md skills/platform-link.md skills/teamserver-alignment.md skills/learned-constants-and-secrets.md" ;; 7) echo "skills/interview-protocol.md skills/grill-mode.md skills/checkpoints/checkpoint-template.md skills/checkpoints/checkpoint-cutover.md skills/close-the-loop.md skills/share-demo-package.md skills/handoff-to-studio-pro.md skills/platform-link.md skills/teamserver-alignment.md skills/deploy-to-sandbox.md" ;; *) echo "" ;; diff --git a/bin/lib/skill-routing.tsv b/bin/lib/skill-routing.tsv index f77eaf3..98ed218 100644 --- a/bin/lib/skill-routing.tsv +++ b/bin/lib/skill-routing.tsv @@ -197,6 +197,7 @@ learned-mdl-cannot-express skills/learned-mdl-cannot-express.md Before a wirefra learned-css-that-never-applied skills/learned-css-that-never-applied.md A style change that appears to have done nothing, or an app still grey after a design port every instrument called green — the three ways a correct rule paints nothing (matches nothing / matches chrome / loses the cascade), the two reads that tell them apart, and the class that arrived in the stylesheet and is bound to no widget mdl,review,gate 5,6 baseline design learned-detection-gaps skills/learned-detection-gaps.md Before trusting a green check/exec/DESCRIBE result as proof, or when a runtime symptom appears over a fully green model — the register of constructs that pass early rungs and fail later ones mdl,gate,review 5,6 baseline diagnose learned-dg2-patterns skills/learned-dg2-patterns.md Building or altering any data grid — native DATAGRID vs pluggable DG2 decision rule, the ALTER PAGE INSERT corruption, sort-by and filter-binding traps mdl 5 ondemand build/pages +learned-file-upload-widget skills/learned-file-upload-widget.md Putting any file upload / attachment / document field on a page, an uploader page failing mx check with CE0463, or an uploader DESCRIBE that will not re-execute — the File Uploader MDL shape proven end to end on v0.23 and v0.24, the widgets mxcli cannot author, and the upload instrument mdl,test 5 ondemand build/pages security-is-not-a-later-script skills/security-is-not-a-later-script.md Creating any entity, or calling a module security-ready — entity and grants land in one script, and ready means SHOW SECURITY MATRIX proves it mdl,gate,review 5 baseline build/security scriptable-sp-verification skills/scriptable-sp-verification.md Needing Studio Pro load evidence without a human at the GUI — direct-binary launch and log capture; a capture technique, NOT a validated pass/fail oracle mdl,gate - ondemand diagnose learned-local-db-confusion skills/learned-local-db-confusion.md A runtime test reads/writes data that then is not there, or vice versa — three local Postgres instances can answer on this box; resolve the real port from the project's own compose file first mdl,test,gate 5,6 ondemand diagnose diff --git a/skills/learned-file-upload-widget.md b/skills/learned-file-upload-widget.md new file mode 100644 index 0000000..8ae288d --- /dev/null +++ b/skills/learned-file-upload-widget.md @@ -0,0 +1,149 @@ +# File upload widget — a file upload mxcli can author, and proof that it uploads + +**Applies to:** any mxcli project +**Purpose:** putting a working file upload on a page: the Mendix File Uploader 2.5.0 pluggable +widget bound to a `System.FileDocument` specialisation, with its create/delete microflows, grants +and allowed formats. Covers which upload widgets mxcli cannot author, the two CE0463 / round-trip +traps with their workarounds, and the instrument that proves an upload works end to end. Load it +before adding any upload/attachment/document field, when an uploader page fails `mx check` with +CE0463, or when a DESCRIBE of an uploader page will not re-execute. +**Source:** a Mendix app-rebuild project, 2026-09-25 (research, then a 6-iteration e2e loop, then a +v0.24.0 re-test). + +--- + +Field-proven 2026-09-25 on Mendix 11.12.2, in throwaway apps made with `mxcli new`, on stock +mxcli **v0.23.0** and again on stock **v0.24.0**. On v0.24.0 the MDL in section 4 was run exactly as +written, taken straight from this file, with only a wrapper around it (module, role, page, menu microflow, +demo user). Result: `mxcli check --references` passed, exec reported 0 errors, `mx check` said +`The app contains: 0 errors.`, and the app booted. A non-admin user uploaded 2/2 files (1024 B .txt, +244 B .zip), both rows had `HasContents true`, both downloads were sha256-equal to the source (2/2 +`MATCH`), and a `.csv` was rejected with 0 rows created. Both traps in section 5 reproduce unchanged on +v0.24.0. + +## 1. Pick the widget + +| Widget | mxcli can author it? | Use it? | +|---|---|---| +| **Mendix File Uploader 2.5.0** (`com.mendix.widget.web.fileuploader.FileUploader`, keyword `fileuploader`) | Yes, on stock v0.23 and v0.24, with the rules below | **Yes.** Proven end to end | +| Classic `Forms$FileManager` (Studio Pro "File manager") | No. No keyword. A `.def.json` gives a false-green `mxcli check`, then exec fails with `template not found: filemanager` | No, until mxcli gets a native `filemanager` (upstream #151) | +| `mendix.PDSFileUploader` | Writes, but stock mxcli gives CE0463 (action variables not written). It also posts to a REST endpoint, not to a FileDocument | Only with a REST backend and a patched mxcli | + +## 2. What the File Uploader needs (it is not a FileManager) + +The File Uploader does not fill the data view's own object. It works on a **context object** and +creates one FileDocument per dropped file: + +1. The widget calls `createFileAction` with the context object. That microflow creates the file + entity, sets the association to the context, and commits it. +2. The widget watches `associatedFiles` (an association path from the context) for the new + object, then POSTs the bytes to `/file?guid=`. +3. On failure it calls `onUploadFailureFile` with the file object, so that microflow can delete it. + +So the domain model is: a context entity, a `System.FileDocument` specialisation, and a reference +from the file to the context. + +## 3. Install + +1. Get the widget `.mpk`. The Marketplace module package (`FileUploader.mpk`, 2.5.0, sha256 + `9e592629…`) contains `widgets/com.mendix.widget.web.FileUploader.mpk`. Copy only that inner file + into the project's `widgets/`. The module's own entities and nanoflows are not needed. +2. Run `mxcli widget init -p App.mpr`. Without it you get `MDL-WIDGET25 fileuploader is not a widget in this project`. + +## 4. The working MDL shape + +```sql +create persistent entity "Uploads"."UploadRequest" ("Title": String(200)); +create persistent entity "Uploads"."Attachment" extends System.FileDocument ("Note": String(200)); +create association "Uploads"."Attachment_UploadRequest" + from "Uploads"."Attachment" to "Uploads"."UploadRequest" type reference; + +-- tested with write * (includes Name and Contents). The module's own reference grant writes Name, Contents and the association; a narrower grant was not tested +grant "Uploads"."User" on "Uploads"."UploadRequest" (create, delete, read *, write *); +grant "Uploads"."User" on "Uploads"."Attachment" (create, delete, read *, write *); + +create microflow "Uploads"."ACT_CreateAttachment" ($UploadRequest: "Uploads"."UploadRequest") +returns "Uploads"."Attachment" as $Attachment +begin + $Attachment = create "Uploads"."Attachment" ("Attachment_UploadRequest" = $UploadRequest); + commit $Attachment with events refresh; + return $Attachment; +end; +/ +create microflow "Uploads"."ACT_DeleteAttachment" ($Attachment: "Uploads"."Attachment") +begin + delete $Attachment; +end; +/ + +-- inside a dataview on the context object: +fileuploader "upFiles" ( + uploadMode: 'files', + associatedFiles: association $currentObject/Uploads.Attachment_UploadRequest, + readOnlyMode: false, + createFileAction: microflow Uploads.ACT_CreateAttachment, + onUploadFailureFile: microflow Uploads.ACT_DeleteAttachment, + maxFileSize: 5, + objectCreationTimeout: 10, + enableCustomButtons: false +) { + allowedfileformat "fmtTxt" (configMode: 'advanced', mimeType: 'text/plain', extensions: '.txt', typeFormatDescription: 'Text file') + allowedfileformat "fmtZip" (configMode: 'advanced', mimeType: 'application/zip', extensions: '.zip', typeFormatDescription: 'ZIP archive') +} +``` + +Also grant `execute` on both microflows to the user's module role. Missing grants give CE0106 at `mx check`. + +**Commit the context object before you open the page.** The menu microflow creates the +`UploadRequest`, commits it, then shows the page. The Save button then only has to commit it again +(or commit and show a result page). An uncommitted context was not tested. + +## 5. The traps, and what to do on stock v0.23 / v0.24 + +Both of the first two traps reproduce unchanged on v0.24.0, which was re-tested 2026-09-25. v0.24's CE0463 fix (#1161) is for +Barcode Scanner's seeded object lists, a different cause. Both are filed upstream: the simple-mode CE0463 as mendixlabs/mxcli#1198, the DESCRIBE round trip as #1199 +(closed #999 and #574 are related but not the same). When a newer mxcli ships, re-probe both on a copy before trusting this table: +(1) change one format to `configMode: 'simple', predefinedType: 'plainTextFile'`, exec, run `mx check`; +(2) `describe page` the uploader page and exec the output unchanged on a copy that differs from it. + +| Trap | Symptom | Stock v0.23 / v0.24 workaround | Proposed fix (proven on a local mxcli build, not upstream yet) | +|---|---|---|---| +| `allowedfileformat` in the default `configMode: 'simple'` (`predefinedType: 'plainTextFile'`) | `mx check`: `[CE0463] "The definition of this widget has changed. ..." at File uploader 'upFiles'`, `The app contains: 1 errors.` | Write every format as `configMode: 'advanced'` with `mimeType`, `extensions` and `typeFormatDescription` | Nested visibility rules applied to object-list items: the hidden required `typeFormatDescription` is written as null (Studio Pro's shape), not as a filled template | +| DESCRIBE of an uploader page, then re-exec | exec: `` widget `upFiles` (fileuploader) exposes 2 datasources, so a generic `datasource:` clause is ambiguous — name the one you mean: associatedFiles, associatedImages `` | Hand-edit the DESCRIBE output: change `DataSource:` to `associatedFiles:` | DESCRIBE names the key when the widget's schema declares more than one datasource | +| Object-list item names | DESCRIBE prints `allowedfileformat1`, not the name you wrote, so `drop widget "fmtTxt"` has nothing to hit later | Replace the whole page (`create or replace page`) to change formats | Not fixed | +| DESCRIBE prints `predefinedType: 'pdfFile'` on advanced items | Re-exec warns `MDL-WIDGET10 ... predefinedType is hidden when its own configMode is not "simple" — the value will be ignored` (a warning; mx check stays 0 errors) | Delete that line from advanced items | Not fixed | +| `mxcli check` says "Check passed!" | Proves nothing for widgets: CE0463 only shows at `mx check` | Always run `mx check` after exec | n/a | +| Re-exec of an identical page | `Unchanged page ...`: nothing was written, so `0 errors` proves nothing about the round trip | Run a round-trip test against a copy where the page differs | n/a | + +With the locally patched build, a simple-mode `.txt` format is shown at runtime as "Plain Text (.txt)" in +the rejection message, so the predefined type does reach the widget. + +## 6. The instrument: what counts as "the upload works" + +`mx check` 0 errors only proves the model is valid. The upload counts as working only when all of these hold: + +1. `mx check`: `The app contains: 0 errors.` +2. The app boots: `mxcli run --local ... --db-type hsqldb --app-port --admin-port --serve-port `. + The default serve port 6543 collides with Studio Pro's own `mxbuild --serve`, so pick a free one. +3. Playwright, logged in as a **non-admin** demo user: open the page, then + `page.locator('.mx-name- input[type=file]').setInputFiles([...])`. Wait until the widget text + shows `Uploaded successfully.` once per file, then click Save. +4. OQL on your own admin port: `mxcli oql -p App.mpr --direct --port "select a.Name, a.Size, a.HasContents from Mod.Attachment a"`. + The default `--port` is 8090. Never let it default when another app is running. +5. Download the file back as the same user (`GET /file?guid=&target=internal` in the logged-in + browser context) and compare its sha256 with the source file. This catches a HasContents=true row that holds the wrong bytes. +6. Negative check: drop a format you did not allow. The widget must show `File format is not supported, ...`, and no row may be created. + +Measured result, stock v0.23 (advanced formats): 1/1 file stored, 1024 bytes, `HasContents true`, sha256 match. +Stock v0.24.0 (advanced .txt and .zip, fresh app): 2/2 files stored (1024 B and 244 B), 2/2 sha256 match, `.csv` +rejected with 0 rows created. +Patched build (simple .txt plus advanced .zip, written from a DESCRIBE round trip): 2/2 files stored +(1024 B and 244 B), both sha256 match, `.csv` rejected with 0 rows created. + +## 7. Not covered + +- Image mode (`uploadMode: 'images'`, `associatedImages`, `System.Image`) was not tested. +- Custom buttons, `maxFilesPerUpload`, and the delete-from-widget path were not tested. +- Only the `mxcli run --local` runtime with HSQLDB was used. Not tested on PostgreSQL, in Docker, or opened in Studio Pro. +- The proposed fixes in section 5 exist only as a local mxcli patch with unit tests (#1198, #1199 describe them). When those issues close, + re-run the simple-mode format and the DESCRIBE round trip before dropping the workarounds.