From 3a1ed1b41ddf61a7497cc57892ff6a5f058c269e Mon Sep 17 00:00:00 2001 From: MendixMau Date: Thu, 15 Oct 2026 22:34:51 +0800 Subject: [PATCH 1/3] learn(workflow, rest): mark the v0.20-era workflow notes superseded for mxcli v0.26.0 (TK-019) WAIT FOR NOTIFICATION takes a name, NOTIFY WORKFLOW needs TARGET, mxcli writes the boundary-path terminator itself, and published REST Authentication: (basic) works (BUG-152 item 1). Verified against mxcli's public write-workflows skill and docs plus a five-app lab field run (Mendix 11.15, mxcli v0.26.0). Situational skills only. Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 1 + bug-logs/mxcli-bugs.md | 3 ++- skills/learned-workflow-patterns.md | 20 ++++++++++++++++---- skills/rest-integration-first-time-right.md | 8 +++++--- skills/workflow-structure-rules.md | 6 +++--- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e238acd..428d01f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m ## Unreleased +- learn(workflow, rest): **the v0.20-era workflow notes are marked superseded for mxcli v0.26.0:** `WAIT FOR NOTIFICATION` takes a name, `NOTIFY WORKFLOW` needs `TARGET Module.Workflow.Element` (CE0166 / MDL-WF16 without), mxcli writes the end-of-boundary-path marker itself so a boundary terminator is no longer a hand-add (the parallel-split terminator is a separate node and unchanged), and published REST `Authentication: (basic)` works (BUG-152 item 1: 401 / 401 / 200 proven, URL includes the resource segment). Sources: a five-app lab field run (Mendix 11.15, mxcli v0.26.0) and mxcli's public `write-workflows` skill and docs. `wf-add-path-terminators.py` already takes an `.mpr` since #294 (the reported crash was the older script). — TK-019 of a five-app lab report - new(mxpatch, exec): **`project-bin/mxpatch.py`, the shared patch core, and a `mxcli fix hashes` check around every `exec.sh --patch` run: the two shipped workflow patchers no longer leave a stale ContentsHash.** mxpatch finds a unit by type + name (+ module) with a byte pre-filter, finds an element by Name, gets/sets a value by key, and writes the unit and its `.mpr` ContentsHash (base64 SHA-256 of the file) in one step; dry run by default, `already applied` on a re-run, and a refusal (exit 3) when the current value is not the expected old one. `wf-set-call-captions.py` and `wf-add-path-terminators.py` now write through it, refuse drift (a caption is replaced only while it is still the stamped microflow name or the `--expect-caption` value; `--expect-paths N` for terminators), and also take the `exec.sh --patch` form (` Module.Workflow`). The index is committed before the file swap, so a kill mid-write leaves a MISMATCH that `fix hashes` reports and a re-run repairs. `mxunit_bson.py` reads BSON 0x09 (UTC datetime). `exec.sh --patch` runs `mxcli fix hashes` (v0.25.0+, probed via `fix --help`) before and after the script and restores the snapshot on any issue the baseline did not have, before mxbuild, which cannot see it. Field evidence: captured mxcli v0.25.0/v0.26.0 runs on a public model (`tests/wave2/fixtures/mxpatch/CAPTURE.txt`): master's patchers leave a MISMATCH, the ported ones verify clean; the hash routine agrees with mxcli on 67 of 67 mismatched and 302 matching units of a second model. Widget-shape copying and pluggable-widget properties wait on a captured page unit. Field run ([#390](https://github.com/MendixMau/mxcli-project-toolkit/issues/390), mxcli v0.26.0, macOS): PASS, and the patch repaired a ContentsHash MISMATCH an old-style `--patch` had left on the unit it rewrote. Fixes from it: the backup of a rewritten unit is kept outside `mprcontents/` (in `$MXPATCH_BACKUP_DIR`, which `exec.sh --patch` points into the snapshot it just took, else a 0700 `/mxpatch-bak-/`; refused when it resolves inside `mprcontents/`, through a symlink or another case spelling; named with pid and counter so two writes in one second keep both), no longer as an untracked `.mxunit.bak` that `git add mprcontents` would commit; the BUILD-LOG row carries the hash bracket (`hashes: baseline 1 mismatch (pre-existing), verify clean (1 pre-existing repaired by this patch's rewrite)`); and the baseline message says that a unit the patch rewrites gets a fresh hash, and to repair the others with `fix hashes --repair`. A baseline MISMATCH that is still reported on a unit the patch rewrote counts as new (restore, exit 1), not as pre-existing. — jopterhorst ([#294](https://github.com/MendixMau/mxcli-project-toolkit/issues/294), [#295](https://github.com/MendixMau/mxcli-project-toolkit/issues/295)) - learn(pipelines/mendix-mpr/samples): **three minimal mxcli repros from the native-module bug hunt, the files the upstream draft cites** (split from [#293](https://github.com/MendixMau/mxcli-project-toolkit/pull/293), 6/6). `fsm-template-9.24.2/native-bughunt/` holds CAPTURE.txt and D1–D3, which are written from scratch in a `Repro` module: `describe entity` printing `index ( desc);`, the native Repeater `content` slot, and no flow writable to a 9.24.2 project. They are the repros for U3, U2 and U14 in `bug-logs/pending-github-issues/2026-10-12-mxcli-0.26-round-trip-report.md`. The other 472 sample files of #293 had no citing reader, because the skills and Rehost splits state their field results inline, so none of them ships. — MendixMau, Decompose/Rehost lab runs 2026-10-12 - learn(inbox, pending-github-issues): **ten field-note drops from the Decompose/Rehost lab runs, and one not-filed draft of 53 mxcli 0.26 defects for mendixlabs/mxcli** (split from [#293](https://github.com/MendixMau/mxcli-project-toolkit/pull/293), 5/6). `contrib/inbox/2026-10-1{2,3}-*.md`: increments 1–8 of the split-a-monolith runs on a public Marketplace template (FSM 9.24.2), the native-module bug hunt, and the GenAI Showcase regeneration (0.26.0 and the 2026-10-13 nightly); each now has the template's front matter and is at most 600 words. `bug-logs/pending-github-issues/2026-10-12-mxcli-0.26-round-trip-report.md`: the U1–U53 table the inbox drops refer to, marked DRAFT — NOT FILED, to be split into one issue per defect and retested before anything is posted. No BUG numbers assigned; triage promotes. — MendixMau, Decompose/Rehost lab runs 2026-10-12/13 diff --git a/bug-logs/mxcli-bugs.md b/bug-logs/mxcli-bugs.md index f2042415..4164ae21 100644 --- a/bug-logs/mxcli-bugs.md +++ b/bug-logs/mxcli-bugs.md @@ -5935,7 +5935,8 @@ list is empty. The endpoint therefore receives the characters `$Var`. service and its callers. **Reproducible:** yes, on scratch copies (`describe` read-back, BSON reads, lint deltas). -1. **No authentication clause.** `create published rest service` has none. An `Authentication:` +1. **SUPERSEDED on v0.26.0 (Mendix 11.15.0): `Authentication: (basic)` works.** A five-app lab run: `create or modify published rest service ... ( Path: '...', Version: '1.0.0', ServiceName: '...', Authentication: (basic) ) { resource 'r' { get 'ping' microflow M.F; } };` plus `grant access on published rest service M.S to M.Role;` and `grant execute on microflow M.F to M.Role;` answered 401 without credentials, 401 with a wrong password, 200 with the right one. The operation URL is service path + resource name + operation path (without the resource segment: 404). Upstream lists `basic`, `session`, `microflow M.F` and `none`. The v0.24.0 finding follows. + **No authentication clause (v0.24.0).** `create published rest service` has none. An `Authentication:` property passes `check` and is silently ignored: the service is written without auth, and every call reaches the operation microflow unauthenticated. `describe` shows no auth. Authenticate inside the operation microflow instead. Then prove it at runtime: no credentials diff --git a/skills/learned-workflow-patterns.md b/skills/learned-workflow-patterns.md index ea88c211..83cc969a 100644 --- a/skills/learned-workflow-patterns.md +++ b/skills/learned-workflow-patterns.md @@ -309,10 +309,12 @@ USER TASK "Review" 'Review' CALL MICROFLOW MyModule."SUB_Remind" WITH ("Request" = '$WorkflowContext'); }; --- wait for timer / wait for notification. WAIT FOR NOTIFICATION takes NO name -- --- 'WAIT FOR NOTIFICATION ''Ping'';' is a parse error; the name is a Studio Pro property. +-- wait for timer / wait for notification. +-- SUPERSEDED on v0.26.0: WAIT FOR NOTIFICATION takes a name (`wait for notification waitDone;`), +-- and a NOTIFY WORKFLOW that targets it needs `TARGET Module.Workflow.waitDone`. On v0.20.0 +-- the named form was a parse error; the bare form still parses on v0.26.0. Name every wait. WAIT FOR TIMER 'addDays([%CurrentDateTime%], 1)'; -WAIT FOR NOTIFICATION; +WAIT FOR NOTIFICATION waitDone; ``` **The two signatures a workflow's own gates check and `mxcli check` does not** (v0.21.0, @@ -445,7 +447,7 @@ manual Studio Pro steps built around a blocker that never existed. | Open an instance | `OPEN WORKFLOW $Wf;` (client action) | | Open a task | `OPEN USER TASK $Task;` (client action) | | Lock / unlock | `LOCK WORKFLOW $Wf;` · `UNLOCK WORKFLOW $Wf;` · `LOCK WORKFLOW ALL;` · `UNLOCK WORKFLOW ALL;` | -| Release a wait | `$R = NOTIFY WORKFLOW $Wf;` (releases a *wait for notification* activity) | +| Release a wait | `$R = NOTIFY WORKFLOW $Wf TARGET Module.Workflow.waitDone;` (releases a *wait for notification* activity; on mxcli v0.26.0 `TARGET` is required, without it `check` refuses: CE0166 / MDL-WF16. The target may be a named wait, a notification activity or a notification boundary event.) | | Instances for a context object | `$Wfs = GET WORKFLOWS FOR $Ctx;` | | Instance metadata | `$D = GET WORKFLOW DATA $Wf AS Mod."Entity";` | | Audit trail | `$Recs = GET WORKFLOW ACTIVITY RECORDS $Wf;` | @@ -1013,6 +1015,16 @@ already exists. ## 19. `BOUNDARY EVENT TIMER` — don't add one without a documented business trigger +> **SUPERSEDED on mxcli v0.26.0 (Mendix 11.15.0, 2026-10-15): the boundary terminator is no longer +> a hand-add.** mxcli writes the end-of-boundary-path marker itself +> (`Workflows$EndOfBoundaryEventPathActivity`), so a boundary path may end in a plain +> `call microflow`; the notification boundary event exists too (`boundary event interrupting +> notification Name 'Caption' { ... }`). Source: mxcli's own `write-workflows` skill and +> `docs-site/src/language/workflow-activities.md`, and a five-app lab field run. A boundary +> terminator pass is not needed; the **parallel split** terminator (§18, §23) is a separate +> node and this note does not change it (not re-probed on v0.26.0). Re-test the notes below +> against your pinned mxcli before relying on them. + > **CORRECTION, 2026-09-03 (probed, mxcli v0.20.0 / Mendix 11.14.0).** The `'P3D'` form below > is **wrong** and was recorded here as proven on a `mxcli check` alone. The timer takes a > Mendix **expression**, not an ISO 8601 period: `'P3D'` passes `mxcli check` and `exec`, then diff --git a/skills/rest-integration-first-time-right.md b/skills/rest-integration-first-time-right.md index 8a27ae75..bff7202a 100644 --- a/skills/rest-integration-first-time-right.md +++ b/skills/rest-integration-first-time-right.md @@ -297,9 +297,11 @@ association direction; all fine, page empty → stale deployment or a different green. Write `body '{1}' with ({1} = $Var)` (BUG-151). - **`import from mapping M($Call/ResponseBody)` is a parse error.** Declare a String first: `declare $Body String = $Call/ResponseBody;` then `M($Body)` (BUG-152). -- **A published REST service has no auth clause**, and an `Authentication:` property is - silently ignored. Authenticate inside the operation microflow, and prove that no credentials - and a wrong password each answer 401 (BUG-152). +- **A published REST service has no auth clause on v0.24.0**, and an `Authentication:` property is + silently ignored there. **On v0.26.0 `Authentication: (basic)` works** (also `session`, + `microflow M.F`, `none`): grant the role access to the service and execute on each backing + microflow, and note the URL includes the resource segment. On either version, prove that no + credentials and a wrong password each answer 401 (BUG-152). - **`create or modify published rest service` replaces the resource list.** One script owns the service and names every resource (BUG-152). - **Extend an import mapping with `create or modify`, never drop and recreate it.** The drop diff --git a/skills/workflow-structure-rules.md b/skills/workflow-structure-rules.md index a265c7cd..4f7f2297 100644 --- a/skills/workflow-structure-rules.md +++ b/skills/workflow-structure-rules.md @@ -325,7 +325,7 @@ row's stated floor is evidence against it. | **a targeting microflow's signature** | **it must accept TWO parameters — `System.Workflow` AND the context entity — in that order.** One parameter is the natural thing to write and it is wrong: *"should accept parameters of type 'System.Workflow' and 'MOC.MOCProject'. Instead the selected microflow expects 'MOC.MOCProject'"*. Again clean through `mxcli check`, caught only by the native build. Neither this signature nor the page's appears in `mxcli syntax workflow.user-task.targeting`, whose own example is `TARGETING MICROFLOW HR.GetApprovers` with no signature stated. Measured v0.21.0, 2026-09-09 | | **multi-user task** — the activity itself | **proven**. Undocumented in `mxcli syntax workflow`; works anyway | | **`JUMP TO `** inside a user-task outcome | **proven** | -| **`WAIT FOR TIMER ''`** and **`WAIT FOR NOTIFICATION;`** | **proven**. Both undocumented; the notification takes **no name** — that is a Studio Pro property | +| **`WAIT FOR TIMER ''`** and **`WAIT FOR NOTIFICATION;`** | **proven**. Both undocumented. **v0.26.0: the notification takes a name** (`wait for notification waitDone;`, the bare form still parses) and `NOTIFY WORKFLOW` needs `TARGET Module.Workflow.waitDone` (CE0166 / MDL-WF16 without). On v0.20.0 the name was a parse error | | **boundary event timer, non-interrupting** | **proven**, with an **expression**, not an ISO period | | ~~decision on a **boolean or free-text** outcome~~ | **RETRACTED 2026-09-03 — see the CORRUPTING row below.** This row read "proven on mxcli ≥ v0.18.0" and it was wrong: BUG-76's v0.20.0 retest corrupts on a condition of literal `1 = 1`. The condition never mattered; the defect is in how the *outcome label* is written. Left visible with a strikethrough rather than deleted, because "a boolean decision is the safe kind" is the belief this table has to actively kill | | call microflow, with or without parameters | **proven** — with two limits. (1) The `WITH` clause's **value must be quoted**: `WITH ("Ctx" = '$WorkflowContext')`. Unquoted (`= $WorkflowContext`) segfaults the binary, BUG-107. (2) **`$WorkflowUserTask` is NOT in scope here** — only `$WorkflowContext` and `$WorkflowInstance` are. Passing it is a **CE0117** that `mxcli check --references` passes completely clean; only mxbuild catches it. A microflow that needs the task looks it up by name off `$WorkflowInstance` through `System.WorkflowEndedUserTask`. Proven by sandbox A/B on a full project copy, 2026-09-04 — this corrects an earlier reading of §8 that treated *call microflow* as having the task | @@ -338,7 +338,7 @@ row's stated floor is evidence against it. | **boundary event on notification** | **hand-add** — the grammar admits `{TIMER, INTERRUPTING, NON}` only | | **event sub-process** (all four start kinds), recurrence | **hand-add** — no construct in the grammar, in any position | | **multi-user decision method / completion timing** | **hand-add** — the activity is scriptable, its decision rule is not | -| **explicit `END WORKFLOW`, end-of-parallel-split-path, end-of-boundary-event-path** | **not expressible — and the "not needed" half of this row was wrong, corrected 2026-09-14.** MDL terminates by nesting and `mx check` accepts it, so the gap is invisible to every gate; the **runtime is not indifferent**. A parallel-split path with no terminator opens no task at all (BUG-121, repaired post-exec by `bin/wf-add-path-terminators.py`), and an empty outcome block meant to stop the instance rejoins the enclosing flow instead (§21 gap 2). One grammar gap, two silent runtime faults. Still true: **CE1844 cannot be triggered from MDL** — §4 governs the diagram and anything hand-added, not the script | +| **explicit `END WORKFLOW`, end-of-parallel-split-path, end-of-boundary-event-path** | **not expressible — and the "not needed" half of this row was wrong, corrected 2026-09-14.** MDL terminates by nesting and `mx check` accepts it, so the gap is invisible to every gate; the **runtime is not indifferent**. A parallel-split path with no terminator opens no task at all (BUG-121, repaired post-exec by `bin/wf-add-path-terminators.py`), and an empty outcome block meant to stop the instance rejoins the enclosing flow instead (§21 gap 2). One grammar gap, two silent runtime faults. **v0.26.0: the end-of-boundary-event-path marker is now written by mxcli itself; the parallel-split terminator is not re-probed.** Still true: **CE1844 cannot be triggered from MDL** — §4 governs the diagram and anything hand-added, not the script | | **user-task `onCreatedEvent`** (the *On created* handler — the mechanism §6 names for assignment carried in data) | **not expressible in MDL, and this is grammar-level, not a docs gap.** The parser enumerates its own alternatives: after `PARAMETER` it accepts only `{BEGIN, EXPORT, DUE, OVERVIEW, DESCRIPTION, DISPLAY}`, and after a user task's `PAGE` only `;`. Four spellings probed (`ON CREATED CALL MICROFLOW`, `ON WORKFLOW EVENT`, task-level `ON CREATED`, `ONCREATEDEVENT`), all rejected at parse. **But it IS on the MCP write path** — `mxcli`'s `CreateWorkflow`/`UpdateWorkflow` payload carries `json:"onCreatedEvent"` on the *user-task* struct, beside `taskPage`, `outcomes` and `boundaryEvents`, and without `omitempty`. So it is a **per-task** property, not one workflow-level handler. End-to-end MCP write **not verified** — that needs a live Studio Pro. Treat as: hand-add in Studio Pro | | **AI agent task activity** | **unprobed** — its model rules (companion microflow first, outcomes mirror its return values, Boolean/Enum/Void only) hold whichever tool writes it | @@ -474,7 +474,7 @@ between people, this decides how many workflows exist and who each task targets. | Multi-instance parallel user task | **Native** — Multi-User Task | proven; decision method + completion timing are a hand-add (§7) | | Service / script / business-rule / manual task | **Native or workaround** — Call Microflow | proven; quote the `WITH` value | | Send task | **Workaround** — Call Microflow + Notify Workflow | proven | -| Receive task | **Native** — Wait for Notification | proven; takes no name | +| Receive task | **Native** — Wait for Notification | proven; v0.26.0 takes a name, and NOTIFY needs `TARGET` | | Call activity / reusable subprocess | **Native** — Call Workflow | proven | | Event sub-process | **Native** | **hand-add** — no MDL construct, in any position (§3, §11) | | Timer: intermediate catch, boundary interrupting/non-interrupting | **Native** | non-interrupting proven; interrupting proven on v0.24.0, **a hand-add on older binaries** (§2, §11) | From 87c593571a8c0863e6375bedd37483474f5d6db2 Mon Sep 17 00:00:00 2001 From: MendixMau Date: Thu, 15 Oct 2026 22:37:15 +0800 Subject: [PATCH 2/3] learn(workflow): compute-then-branch pattern and called-microflow limits (TK-023) Situational skills only; sources and field evidence in CHANGELOG. Verified claims are marked as field observations where mxcli/Mendix docs did not confirm them. Co-Authored-By: Claude Sonnet 5.5 --- CHANGELOG.md | 1 + skills/workflow-structure-rules.md | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 428d01f9..187ef8ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m ## Unreleased - learn(workflow, rest): **the v0.20-era workflow notes are marked superseded for mxcli v0.26.0:** `WAIT FOR NOTIFICATION` takes a name, `NOTIFY WORKFLOW` needs `TARGET Module.Workflow.Element` (CE0166 / MDL-WF16 without), mxcli writes the end-of-boundary-path marker itself so a boundary terminator is no longer a hand-add (the parallel-split terminator is a separate node and unchanged), and published REST `Authentication: (basic)` works (BUG-152 item 1: 401 / 401 / 200 proven, URL includes the resource segment). Sources: a five-app lab field run (Mendix 11.15, mxcli v0.26.0) and mxcli's public `write-workflows` skill and docs. `wf-add-path-terminators.py` already takes an `.mpr` since #294 (the reported crash was the older script). — TK-019 of a five-app lab report +- learn(workflow): **a "compute, then branch" pattern in `workflow-structure-rules.md`: a workflow decision reads a Boolean or enumeration on the context and cannot call a microflow, so the rule is computed by an earlier call microflow into a context attribute (TK-023).** The same paragraph names the three limits a field run hit (called microflow returns Boolean, enumeration or nothing; decision expressions on the context only; single-outcome user task holds no activities, MDL-WF02 / CE1876). The call-microflow return rule and the lone-outcome rule were already in the skill (§5, `learned-workflow-patterns.md` §6); the report's claim that an `exposed as workflow action` microflow cannot return a value was not adopted, because mxcli's own docs show one with `returns String`. — five-app lab report, TK-023 - new(mxpatch, exec): **`project-bin/mxpatch.py`, the shared patch core, and a `mxcli fix hashes` check around every `exec.sh --patch` run: the two shipped workflow patchers no longer leave a stale ContentsHash.** mxpatch finds a unit by type + name (+ module) with a byte pre-filter, finds an element by Name, gets/sets a value by key, and writes the unit and its `.mpr` ContentsHash (base64 SHA-256 of the file) in one step; dry run by default, `already applied` on a re-run, and a refusal (exit 3) when the current value is not the expected old one. `wf-set-call-captions.py` and `wf-add-path-terminators.py` now write through it, refuse drift (a caption is replaced only while it is still the stamped microflow name or the `--expect-caption` value; `--expect-paths N` for terminators), and also take the `exec.sh --patch` form (` Module.Workflow`). The index is committed before the file swap, so a kill mid-write leaves a MISMATCH that `fix hashes` reports and a re-run repairs. `mxunit_bson.py` reads BSON 0x09 (UTC datetime). `exec.sh --patch` runs `mxcli fix hashes` (v0.25.0+, probed via `fix --help`) before and after the script and restores the snapshot on any issue the baseline did not have, before mxbuild, which cannot see it. Field evidence: captured mxcli v0.25.0/v0.26.0 runs on a public model (`tests/wave2/fixtures/mxpatch/CAPTURE.txt`): master's patchers leave a MISMATCH, the ported ones verify clean; the hash routine agrees with mxcli on 67 of 67 mismatched and 302 matching units of a second model. Widget-shape copying and pluggable-widget properties wait on a captured page unit. Field run ([#390](https://github.com/MendixMau/mxcli-project-toolkit/issues/390), mxcli v0.26.0, macOS): PASS, and the patch repaired a ContentsHash MISMATCH an old-style `--patch` had left on the unit it rewrote. Fixes from it: the backup of a rewritten unit is kept outside `mprcontents/` (in `$MXPATCH_BACKUP_DIR`, which `exec.sh --patch` points into the snapshot it just took, else a 0700 `/mxpatch-bak-/`; refused when it resolves inside `mprcontents/`, through a symlink or another case spelling; named with pid and counter so two writes in one second keep both), no longer as an untracked `.mxunit.bak` that `git add mprcontents` would commit; the BUILD-LOG row carries the hash bracket (`hashes: baseline 1 mismatch (pre-existing), verify clean (1 pre-existing repaired by this patch's rewrite)`); and the baseline message says that a unit the patch rewrites gets a fresh hash, and to repair the others with `fix hashes --repair`. A baseline MISMATCH that is still reported on a unit the patch rewrote counts as new (restore, exit 1), not as pre-existing. — jopterhorst ([#294](https://github.com/MendixMau/mxcli-project-toolkit/issues/294), [#295](https://github.com/MendixMau/mxcli-project-toolkit/issues/295)) - learn(pipelines/mendix-mpr/samples): **three minimal mxcli repros from the native-module bug hunt, the files the upstream draft cites** (split from [#293](https://github.com/MendixMau/mxcli-project-toolkit/pull/293), 6/6). `fsm-template-9.24.2/native-bughunt/` holds CAPTURE.txt and D1–D3, which are written from scratch in a `Repro` module: `describe entity` printing `index ( desc);`, the native Repeater `content` slot, and no flow writable to a 9.24.2 project. They are the repros for U3, U2 and U14 in `bug-logs/pending-github-issues/2026-10-12-mxcli-0.26-round-trip-report.md`. The other 472 sample files of #293 had no citing reader, because the skills and Rehost splits state their field results inline, so none of them ships. — MendixMau, Decompose/Rehost lab runs 2026-10-12 - learn(inbox, pending-github-issues): **ten field-note drops from the Decompose/Rehost lab runs, and one not-filed draft of 53 mxcli 0.26 defects for mendixlabs/mxcli** (split from [#293](https://github.com/MendixMau/mxcli-project-toolkit/pull/293), 5/6). `contrib/inbox/2026-10-1{2,3}-*.md`: increments 1–8 of the split-a-monolith runs on a public Marketplace template (FSM 9.24.2), the native-module bug hunt, and the GenAI Showcase regeneration (0.26.0 and the 2026-10-13 nightly); each now has the template's front matter and is at most 600 words. `bug-logs/pending-github-issues/2026-10-12-mxcli-0.26-round-trip-report.md`: the U1–U53 table the inbox drops refer to, marked DRAFT — NOT FILED, to be split into one issue per defect and retested before anything is posted. No BUG numbers assigned; triage promotes. — MendixMau, Decompose/Rehost lab runs 2026-10-12/13 diff --git a/skills/workflow-structure-rules.md b/skills/workflow-structure-rules.md index 4f7f2297..59b2ce27 100644 --- a/skills/workflow-structure-rules.md +++ b/skills/workflow-structure-rules.md @@ -272,6 +272,27 @@ Anything genuinely needing `$currentUser` is a *call microflow*, which has it `learned-workflow-patterns.md` §15 adds the mxcli-side limit: no bracketed association filter in a decision expression — that is a microflow with a `RETRIEVE`. +**Compute, then branch.** A *decision* reads an expression on the context; it cannot call a +microflow. When the rule needs logic (a threshold, a lookup, a count), do not wrap it in a +microflow the decision calls. Write the result to a **Boolean (or enumeration) attribute on the +context entity** in a *call microflow* that runs earlier in the flow, then branch on it: + +``` +call microflow Mod.ACT_Review_Evaluate (Case = $WorkflowContext) as cmEvaluate; -- sets Case/NeedsSecond +decision decSecond $WorkflowContext/NeedsSecond + outcomes true -> { user task ... } false -> { }; +``` + +Three limits the same field run hit, none of which `check` explains well (mxcli v0.26.0, Mendix +11.15, one five-app lab project): (a) a microflow *called from a workflow* returns **Boolean, an +enumeration or nothing** (`learned-workflow-patterns.md` §6), so hand a computed value back by +storing it on the context entity, not through a `String` or entity return; (b) a decision's +condition is a Boolean or enumeration expression on `$WorkflowContext` or `$WorkflowInstance` +only, hence the stored attribute above; (c) a user task with a single outcome holds no +activities in that outcome (`MDL-WF02` / CE1876): put the call **after** the task (§5). A +"compute then branch" call microflow also needs its result attribute to exist before the +workflow script runs, so the entity script comes first. + ## 9. Versioning — which edits break running instances Relevant the moment a workflow is redeployed with live cases (migration cutover, any Stage 6+ From 8818f7b0b35cb94e12ef4e58a307910f4b3200db Mon Sep 17 00:00:00 2001 From: MendixMau Date: Thu, 15 Oct 2026 23:00:01 +0800 Subject: [PATCH 3/3] docs(workflow): align example and counterpart rows with v0.26.0 notes (review #401) Use the proven quoted call-microflow WITH and Boolean keyword decision forms in the compute-then-branch example, note the v0.26.0 notification boundary event, and update the workflow example for named waits and NOTIFY TARGET. Co-Authored-By: Claude Opus 5.5 --- skills/build/workflow-example.mdl | 8 +++++--- skills/workflow-structure-rules.md | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/skills/build/workflow-example.mdl b/skills/build/workflow-example.mdl index 1374cd9a..df5307dc 100644 --- a/skills/build/workflow-example.mdl +++ b/skills/build/workflow-example.mdl @@ -348,7 +348,7 @@ END; -- OPEN WORKFLOW $Wf; -- OPEN USER TASK $Task; -- LOCK WORKFLOW $Wf; UNLOCK WORKFLOW $Wf; UNLOCK WORKFLOW ALL; --- $R = NOTIFY WORKFLOW $Wf; +-- $R = NOTIFY WORKFLOW $Wf TARGET Mod.Wf.waitDone; -- v0.26.0: TARGET required (CE0166) -- $Wfs = GET WORKFLOWS FOR $Ctx; -- $D = GET WORKFLOW DATA $Wf AS Mod."Entity"; -- $Recs = GET WORKFLOW ACTIVITY RECORDS $Wf; @@ -432,10 +432,12 @@ END; -- }; -- 4. WAIT FOR TIMER / WAIT FOR NOTIFICATION. --- WAIT FOR NOTIFICATION takes NO name -- the name is a Studio Pro property. +-- v0.26.0: WAIT FOR NOTIFICATION takes a name (the bare form still parses); +-- a NOTIFY WORKFLOW needs TARGET Module.Workflow.. On v0.20.0 the name +-- was a parse error. -- -- WAIT FOR TIMER 'addDays([%CurrentDateTime%], 1)'; --- WAIT FOR NOTIFICATION; +-- WAIT FOR NOTIFICATION waitDone; -- 5. TARGETING XPATH, token form -- now proven alongside the three-segment -- path form. Double the inner quotes. diff --git a/skills/workflow-structure-rules.md b/skills/workflow-structure-rules.md index 59b2ce27..13caf127 100644 --- a/skills/workflow-structure-rules.md +++ b/skills/workflow-structure-rules.md @@ -278,9 +278,9 @@ microflow the decision calls. Write the result to a **Boolean (or enumeration) a context entity** in a *call microflow* that runs earlier in the flow, then branch on it: ``` -call microflow Mod.ACT_Review_Evaluate (Case = $WorkflowContext) as cmEvaluate; -- sets Case/NeedsSecond -decision decSecond $WorkflowContext/NeedsSecond - outcomes true -> { user task ... } false -> { }; +call microflow Mod.ACT_Review_Evaluate with ("Case" = '$WorkflowContext'); -- sets Case/NeedsSecond +decision decSecond '$WorkflowContext/NeedsSecond' + outcomes true -> { user task ... } false -> { }; -- Boolean keyword form proven in §11 (BUG-76) ``` Three limits the same field run hit, none of which `check` explains well (mxcli v0.26.0, Mendix @@ -356,7 +356,7 @@ row's stated floor is evidence against it. | **parallel split**, incl. **nested** | **proven on v0.21.0 — with one mandatory post-exec step**, which is the whole of §4's warning above and `learned-workflow-patterns.md` §18. The structure writes correctly at any depth; the `EndOfParallelSplitPathActivity` that closes each path does not, and MDL has no keyword for it. Add it with `bin/wf-add-path-terminators.py --apply` after this script **and after every later script that rewrites the workflow** (§23), then verify with a live run, never a gate. BUG-121; field-proven 8-of-16 → **16-of-16 stations, 6 concurrent**. This row read RETRACTED until 2026-09-14 | | **forward `JUMP TO`** (target later in the flow than the outcome jumping to it) | **proven on v0.24.0 / Mendix 11.13.0 — this row taught CE6681 until 2026-09-26, and direction was never the platform rule.** Re-probed as an intended known-bad control (a card-disbursement requirements-driven build): `check --references`, `exec` and native `mx check` all 0 errors, and `DESCRIBE` reads the jump back with its real target. The CE6681 recorded here came from mxcli's jump-named-after-its-target defect, for which forward order was the broken case; upstream `825873d6` fixed it in v0.21.0 (`learned-workflow-patterns.md` §25). On a binary older than v0.21.0, jump backwards or hand-add. A CE6681 on a jump now means the target does not resolve — see the reject-path paragraph below the table | | **boundary event timer, interrupting** | **proven on v0.24.0 / Mendix 11.13.0** (2026-09-26, a card-disbursement requirements-driven build): a body that calls a microflow and then ends in `end workflow comment '…';`, or in `jump to ;`, passes check, exec and native `mx check` at 0 errors, and the read-back shows a real jump with a real target — BUG-109 no longer reproduces. The path must still end in *End* or *Jump* (CE0105 on an empty body), and §2's one-interrupting-boundary rule applies. **Before v0.24.0: hand-add** — `end workflow` did not parse before the post-v0.22.0 nightly, and `JUMP TO` there was BUG-109 through v0.20.0 | -| **boundary event on notification** | **hand-add** — the grammar admits `{TIMER, INTERRUPTING, NON}` only | +| **boundary event on notification** | **hand-add before v0.26.0** — the grammar admitted `{TIMER, INTERRUPTING, NON}` only. **v0.26.0: `boundary event interrupting notification` exists** (`learned-workflow-patterns.md` §19) | | **event sub-process** (all four start kinds), recurrence | **hand-add** — no construct in the grammar, in any position | | **multi-user decision method / completion timing** | **hand-add** — the activity is scriptable, its decision rule is not | | **explicit `END WORKFLOW`, end-of-parallel-split-path, end-of-boundary-event-path** | **not expressible — and the "not needed" half of this row was wrong, corrected 2026-09-14.** MDL terminates by nesting and `mx check` accepts it, so the gap is invisible to every gate; the **runtime is not indifferent**. A parallel-split path with no terminator opens no task at all (BUG-121, repaired post-exec by `bin/wf-add-path-terminators.py`), and an empty outcome block meant to stop the instance rejoins the enclosing flow instead (§21 gap 2). One grammar gap, two silent runtime faults. **v0.26.0: the end-of-boundary-event-path marker is now written by mxcli itself; the parallel-split terminator is not re-probed.** Still true: **CE1844 cannot be triggered from MDL** — §4 governs the diagram and anything hand-added, not the script |