From 2a4cb856eff0c3ae8d2a1900e2090e028ed0efca Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Mon, 7 Sep 2026 22:51:57 +0200 Subject: [PATCH 1/8] Add runmodal-is-not-allowed-inside-write-transactions.md; drop "modal page" from the prompts article A modal page does not behave like Confirm/StrMenu inside a write transaction: the platform refuses Page.RunModal (and Report/XmlPort .RunModal with a request page, and Codeunit.Run with its return value used) with a runtime error instead of holding the lock. The new article documents that guard - verified against Microsoft Learn (Codeunit.Run transaction semantics), microsoft/AL#5452, Microsoft's own Base Application (Commit(); Page.RunModal pattern), and a live reproduction on Business Central 26 quoted verbatim. avoid-user-prompts-inside- transactions.md keeps its scope to the prompts the platform does allow; "modal page" is removed from its list because that case is refused, not stalled. Co-Authored-By: Claude Fable 5.1 --- .../avoid-user-prompts-inside-transactions.md | 2 +- ...t-allowed-inside-write-transactions.bad.al | 18 +++++++++ ...-allowed-inside-write-transactions.good.al | 18 +++++++++ ...s-not-allowed-inside-write-transactions.md | 37 +++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.bad.al create mode 100644 microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.good.al create mode 100644 microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md diff --git a/microsoft/knowledge/performance/avoid-user-prompts-inside-transactions.md b/microsoft/knowledge/performance/avoid-user-prompts-inside-transactions.md index bb03f416..f871c987 100644 --- a/microsoft/knowledge/performance/avoid-user-prompts-inside-transactions.md +++ b/microsoft/knowledge/performance/avoid-user-prompts-inside-transactions.md @@ -11,7 +11,7 @@ application-area: [all] ## Description -A `Confirm`, `StrMenu`, modal page, or other user prompt issued from inside a write transaction stalls the transaction — and therefore every lock it holds — until the user responds. Per the upstream guidance, "Avoid user interactions (Confirm, StrMenu) inside transactions — they hold locks while waiting for user input." The wait is bounded only by the user; meanwhile other sessions block on whatever this transaction has acquired. +A `Confirm`, `StrMenu`, or other user prompt issued from inside a write transaction stalls the transaction — and therefore every lock it holds — until the user responds. Per the upstream guidance, "Avoid user interactions (Confirm, StrMenu) inside transactions — they hold locks while waiting for user input." The wait is bounded only by the user; meanwhile other sessions block on whatever this transaction has acquired. ## Best Practice diff --git a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.bad.al b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.bad.al new file mode 100644 index 00000000..665520b7 --- /dev/null +++ b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.bad.al @@ -0,0 +1,18 @@ +codeunit 50258 "Perf Sample RunModalInTxn Bad" +{ + procedure ChangeShippingAgent(DocNo: Code[20]) + var + SalesHeader: Record "Sales Header"; + ShippingAgent: Record "Shipping Agent"; + begin + SalesHeader.Get(SalesHeader."Document Type"::Order, DocNo); + SalesHeader."Shipment Date" := WorkDate(); + SalesHeader.Modify(true); // a write transaction is now open + + // Runtime error: RunModal is not allowed in write transactions. + if Page.RunModal(Page::"Shipping Agents", ShippingAgent) = Action::LookupOK then begin + SalesHeader.Validate("Shipping Agent Code", ShippingAgent.Code); + SalesHeader.Modify(true); + end; + end; +} diff --git a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.good.al b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.good.al new file mode 100644 index 00000000..0fcfcb2c --- /dev/null +++ b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.good.al @@ -0,0 +1,18 @@ +codeunit 50259 "Perf Sample RunModalInTxn Good" +{ + procedure ChangeShippingAgent(DocNo: Code[20]) + var + SalesHeader: Record "Sales Header"; + ShippingAgent: Record "Shipping Agent"; + begin + // User interaction first, while no write transaction is open. + if Page.RunModal(Page::"Shipping Agents", ShippingAgent) <> Action::LookupOK then + exit; + + // All writes after the choice is made; the transaction ends with the trigger. + SalesHeader.Get(SalesHeader."Document Type"::Order, DocNo); + SalesHeader."Shipment Date" := WorkDate(); + SalesHeader.Validate("Shipping Agent Code", ShippingAgent.Code); + SalesHeader.Modify(true); + end; +} diff --git a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md new file mode 100644 index 00000000..f85a0cdb --- /dev/null +++ b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md @@ -0,0 +1,37 @@ +--- +bc-version: [all] +domain: performance +keywords: [runmodal, page-runmodal, report-runmodal, xmlport-runmodal, write-transaction, commit, requestpage, runtime-error] +technologies: [al] +countries: [w1] +application-area: [all] +--- + +# RunModal is not allowed inside a write transaction + +## Description + +Once AL code has written to the database in the current transaction — an `Insert`, `Modify`, or `Delete` with no `Commit` since — the platform refuses to open a modal object until that transaction is committed. `Page.RunModal` fails unconditionally. `Report.RunModal` and `XmlPort.RunModal` fail when they would show a request page; with it suppressed — `Report.RunModal(ReportId, false)`, where the second argument is `RequestWindow`, or `UseRequestPage(false)` on a report instance — they are allowed. `Codeunit.Run` fails when its Boolean return value is used (`if Codeunit.Run() then`), because that form commits — see `codeunit-run-requires-prior-commit-inside-transaction.md`. This is a runtime error, not a compiler diagnostic: the code builds, and the first execution that reaches the call with an open write transaction dies. The guard keys on transaction state alone, not on any relation between what was written and what is opened: an `Item.Insert()` followed by `Page.RunModal(Page::"Customer Card")` — an unrelated table — fails on the `RunModal` line, and because the error stops the transaction, the insert rolls back with it. + +The platform's message (Business Central 26, reproduced 2026-09-07) reads: "The following AL methods are limited during write transactions because one or more tables will be locked: Form.RunModal, Codeunit.Run, Report.RunModal, XmlPort.RunModal. Form.RunModal is not allowed in write transactions. Codeunit.Run is allowed in write transactions only if the return value is not used. For example, 'OK := Codeunit.Run()' is not allowed. Report.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'Report.RunModal(...,false)' is allowed. XmlPort.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'XmlPort.RunModal(...,false)' is allowed. Use the commit method to save the changes before this call, or structure the code differently." The message still uses the legacy names `Form.RunModal` and `RequestForm` even though the AL method is `Page.RunModal` and the report parameter is `RequestWindow`; older versions said "C/AL functions" instead of "AL methods" (microsoft/AL#5452, 2019). The behavior is unchanged across versions. + +The reason is the same one behind `avoid-user-prompts-inside-transactions.md`: a modal object waits for the user, and the platform will not let a write transaction — and every lock it holds — sit open for as long as that takes. The difference is enforcement. `Confirm`, `StrMenu`, and `Message` are *allowed* inside a write transaction and silently hold the locks; `RunModal` is *refused*. Both point at the same design fix. + +## Best Practice + +Sequence the work so the modal interaction happens before the write phase: run the lookup or dialog page first, then perform the writes the user's choice requires, and let the transaction end. When a modal object genuinely must follow a write, `Commit()` first — but only when the state written so far is complete and safe to persist on its own, because that Commit is a real transaction boundary, not a formality. Microsoft's own Base Application follows exactly this pattern where the preceding state is final (`ActivityLog.Table.al` commits the log entry before `Page.RunModal(Page::"Activity Log", Rec)`; `DocumentSendingProfile.Table.al` commits before `Page.RunModal(Page::"Select Sending Options", …)`). For a report or XMLport, suppressing the request page (`UseRequestPage(false)`) is a legitimate way to run it inside a write transaction when no user input is needed. `Database.IsInWriteTransaction()` (runtime 11.0+) lets library code that cannot control its caller detect the state, with the same caveat as the Codeunit.Run article: branching production flow on it usually signals unclear transaction ownership. + +See sample: `runmodal-is-not-allowed-inside-write-transactions.good.al`. + +## Anti Pattern + +Writing to the database and then calling `Page.RunModal` (or a report/XMLport with its request page) in the same trigger — the first production run hits the runtime error. The reflexive fixes are worse than the error: dropping in `Commit()` to silence it persists a half-finished state that can no longer roll back with the rest of the operation, and swapping the page for a `Confirm` or `StrMenu` to "avoid the error" trades a loud failure for the silent lock-holding that `avoid-user-prompts-inside-transactions.md` warns about. + +See sample: `runmodal-is-not-allowed-inside-write-transactions.bad.al`. + +## Source + +- Microsoft Learn, `Codeunit.Run` transaction semantics ("If you're already in a transaction you must commit first before calling Codeunit.Run"): https://learn.microsoft.com/dynamics365/business-central/dev-itpro/developer/methods-auto/codeunit/codeunit-run-method +- microsoft/AL issue #5452 (verbatim English error text, reproduced on "any current version of Business Central", 2019-11-13): https://github.com/microsoft/AL/issues/5452 +- Reproduced 2026-09-07 on Business Central 26 (runtime error dialog, English and Danish clients): a page `OnAction` doing `Item.Insert()` then `Page.RunModal(Page::"Customer Card")` fails with the text quoted in the Description, the AL call stack pointing at the `RunModal` line, and the dialog stating that the transaction was stopped. +- Microsoft Base Application (BCApps, W1): the `Commit(); … Page.RunModal(…)` pattern in `Modules/System/Logging/ActivityLog.Table.al`, `Foundation/Reporting/DocumentSendingProfile.Table.al`, `Bank/Setup/PaymentServiceSetup.Table.al`, and others; BCApps test suites annotate the same guard as "COMMIT is required for Write Transaction Error" (`Tests/General Journal/ERMTestMultipleGenJnlLines.Codeunit.al`). From 6227125cecbe4ba150ae7c03581233d20176733b Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Mon, 7 Sep 2026 22:55:00 +0200 Subject: [PATCH 2/8] Do not list Message among the lock-holding prompts Message runs asynchronously - it is queued and shown when the calling method ends or another method requests input - so it never pauses the transaction and holds no lock. Only Confirm and StrMenu wait for the user. Co-Authored-By: Claude Fable 5.1 --- .../runmodal-is-not-allowed-inside-write-transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md index f85a0cdb..5491c52a 100644 --- a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md +++ b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md @@ -15,7 +15,7 @@ Once AL code has written to the database in the current transaction — an `Inse The platform's message (Business Central 26, reproduced 2026-09-07) reads: "The following AL methods are limited during write transactions because one or more tables will be locked: Form.RunModal, Codeunit.Run, Report.RunModal, XmlPort.RunModal. Form.RunModal is not allowed in write transactions. Codeunit.Run is allowed in write transactions only if the return value is not used. For example, 'OK := Codeunit.Run()' is not allowed. Report.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'Report.RunModal(...,false)' is allowed. XmlPort.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'XmlPort.RunModal(...,false)' is allowed. Use the commit method to save the changes before this call, or structure the code differently." The message still uses the legacy names `Form.RunModal` and `RequestForm` even though the AL method is `Page.RunModal` and the report parameter is `RequestWindow`; older versions said "C/AL functions" instead of "AL methods" (microsoft/AL#5452, 2019). The behavior is unchanged across versions. -The reason is the same one behind `avoid-user-prompts-inside-transactions.md`: a modal object waits for the user, and the platform will not let a write transaction — and every lock it holds — sit open for as long as that takes. The difference is enforcement. `Confirm`, `StrMenu`, and `Message` are *allowed* inside a write transaction and silently hold the locks; `RunModal` is *refused*. Both point at the same design fix. +The reason is the same one behind `avoid-user-prompts-inside-transactions.md`: a modal object waits for the user, and the platform will not let a write transaction — and every lock it holds — sit open for as long as that takes. The difference is enforcement. `Confirm` and `StrMenu` are *allowed* inside a write transaction and silently hold the locks; `RunModal` is *refused*. Both point at the same design fix. ## Best Practice From cfe592fde9edc24ce9efb72b6fa7285a237657e3 Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Mon, 7 Sep 2026 23:06:15 +0200 Subject: [PATCH 3/8] State the four write-transaction conditions as one explicit line per method Mirrors the structure of the platform's own error message so the Report.RunModal and XmlPort.RunModal request-page exceptions are visible at a glance instead of buried in prose. Co-Authored-By: Claude Fable 5.1 --- .../runmodal-is-not-allowed-inside-write-transactions.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md index 5491c52a..aa4b84e0 100644 --- a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md +++ b/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md @@ -11,7 +11,14 @@ application-area: [all] ## Description -Once AL code has written to the database in the current transaction — an `Insert`, `Modify`, or `Delete` with no `Commit` since — the platform refuses to open a modal object until that transaction is committed. `Page.RunModal` fails unconditionally. `Report.RunModal` and `XmlPort.RunModal` fail when they would show a request page; with it suppressed — `Report.RunModal(ReportId, false)`, where the second argument is `RequestWindow`, or `UseRequestPage(false)` on a report instance — they are allowed. `Codeunit.Run` fails when its Boolean return value is used (`if Codeunit.Run() then`), because that form commits — see `codeunit-run-requires-prior-commit-inside-transaction.md`. This is a runtime error, not a compiler diagnostic: the code builds, and the first execution that reaches the call with an open write transaction dies. The guard keys on transaction state alone, not on any relation between what was written and what is opened: an `Item.Insert()` followed by `Page.RunModal(Page::"Customer Card")` — an unrelated table — fails on the `RunModal` line, and because the error stops the transaction, the insert rolls back with it. +Once AL code has written to the database in the current transaction — an `Insert`, `Modify`, or `Delete` with no `Commit` since — the platform restricts four methods until that transaction is committed. The exact conditions, as enforced: + +- `Page.RunModal` — not allowed in a write transaction, under any circumstances. +- `Report.RunModal` — allowed only if the request page is suppressed: `Report.RunModal(ReportId, false)` (the second argument is `RequestWindow`), or `UseRequestPage(false)` on a report instance. With a request page it fails. +- `XmlPort.RunModal` — same rule: allowed only if the request page is suppressed, `XmlPort.RunModal(..., false)`. With a request page it fails. +- `Codeunit.Run` — allowed only if its Boolean return value is not used. `OK := Codeunit.Run()` and `if Codeunit.Run() then` fail, because that form commits — see `codeunit-run-requires-prior-commit-inside-transaction.md`. + +This is a runtime error, not a compiler diagnostic: the code builds, and the first execution that reaches the call with an open write transaction dies. The guard keys on transaction state alone, not on any relation between what was written and what is opened: an `Item.Insert()` followed by `Page.RunModal(Page::"Customer Card")` — an unrelated table — fails on the `RunModal` line, and because the error stops the transaction, the insert rolls back with it. The platform's message (Business Central 26, reproduced 2026-09-07) reads: "The following AL methods are limited during write transactions because one or more tables will be locked: Form.RunModal, Codeunit.Run, Report.RunModal, XmlPort.RunModal. Form.RunModal is not allowed in write transactions. Codeunit.Run is allowed in write transactions only if the return value is not used. For example, 'OK := Codeunit.Run()' is not allowed. Report.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'Report.RunModal(...,false)' is allowed. XmlPort.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'XmlPort.RunModal(...,false)' is allowed. Use the commit method to save the changes before this call, or structure the code differently." The message still uses the legacy names `Form.RunModal` and `RequestForm` even though the AL method is `Page.RunModal` and the report parameter is `RequestWindow`; older versions said "C/AL functions" instead of "AL methods" (microsoft/AL#5452, 2019). The behavior is unchanged across versions. From 1e5d901bd4cdcf88c99adb6f3fafe39b193e428b Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Mon, 7 Sep 2026 23:15:00 +0200 Subject: [PATCH 4/8] Title the article after the platform error it explains "AL methods limited during write transactions: commit before RunModal and Codeunit.Run" - so a developer or agent searching for the runtime error text lands on the one article that covers all four restricted methods. Slug and sample stems renamed to match; keywords gain the error's own phrase and the legacy Form.RunModal name it still uses. Co-Authored-By: Claude Fable 5.1 --- ...> al-methods-limited-during-write-transactions.bad.al} | 0 ... al-methods-limited-during-write-transactions.good.al} | 0 ...md => al-methods-limited-during-write-transactions.md} | 8 ++++---- 3 files changed, 4 insertions(+), 4 deletions(-) rename microsoft/knowledge/performance/{runmodal-is-not-allowed-inside-write-transactions.bad.al => al-methods-limited-during-write-transactions.bad.al} (100%) rename microsoft/knowledge/performance/{runmodal-is-not-allowed-inside-write-transactions.good.al => al-methods-limited-during-write-transactions.good.al} (100%) rename microsoft/knowledge/performance/{runmodal-is-not-allowed-inside-write-transactions.md => al-methods-limited-during-write-transactions.md} (93%) diff --git a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.bad.al b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.bad.al similarity index 100% rename from microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.bad.al rename to microsoft/knowledge/performance/al-methods-limited-during-write-transactions.bad.al diff --git a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.good.al b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.good.al similarity index 100% rename from microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.good.al rename to microsoft/knowledge/performance/al-methods-limited-during-write-transactions.good.al diff --git a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md similarity index 93% rename from microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md rename to microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md index aa4b84e0..c22959ad 100644 --- a/microsoft/knowledge/performance/runmodal-is-not-allowed-inside-write-transactions.md +++ b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md @@ -1,13 +1,13 @@ --- bc-version: [all] domain: performance -keywords: [runmodal, page-runmodal, report-runmodal, xmlport-runmodal, write-transaction, commit, requestpage, runtime-error] +keywords: [limited-during-write-transactions, write-transaction, runmodal, form-runmodal, page-runmodal, report-runmodal, xmlport-runmodal, codeunit-run, commit, requestpage, runtime-error] technologies: [al] countries: [w1] application-area: [all] --- -# RunModal is not allowed inside a write transaction +# AL methods limited during write transactions: commit before RunModal and Codeunit.Run ## Description @@ -28,13 +28,13 @@ The reason is the same one behind `avoid-user-prompts-inside-transactions.md`: a Sequence the work so the modal interaction happens before the write phase: run the lookup or dialog page first, then perform the writes the user's choice requires, and let the transaction end. When a modal object genuinely must follow a write, `Commit()` first — but only when the state written so far is complete and safe to persist on its own, because that Commit is a real transaction boundary, not a formality. Microsoft's own Base Application follows exactly this pattern where the preceding state is final (`ActivityLog.Table.al` commits the log entry before `Page.RunModal(Page::"Activity Log", Rec)`; `DocumentSendingProfile.Table.al` commits before `Page.RunModal(Page::"Select Sending Options", …)`). For a report or XMLport, suppressing the request page (`UseRequestPage(false)`) is a legitimate way to run it inside a write transaction when no user input is needed. `Database.IsInWriteTransaction()` (runtime 11.0+) lets library code that cannot control its caller detect the state, with the same caveat as the Codeunit.Run article: branching production flow on it usually signals unclear transaction ownership. -See sample: `runmodal-is-not-allowed-inside-write-transactions.good.al`. +See sample: `al-methods-limited-during-write-transactions.good.al`. ## Anti Pattern Writing to the database and then calling `Page.RunModal` (or a report/XMLport with its request page) in the same trigger — the first production run hits the runtime error. The reflexive fixes are worse than the error: dropping in `Commit()` to silence it persists a half-finished state that can no longer roll back with the rest of the operation, and swapping the page for a `Confirm` or `StrMenu` to "avoid the error" trades a loud failure for the silent lock-holding that `avoid-user-prompts-inside-transactions.md` warns about. -See sample: `runmodal-is-not-allowed-inside-write-transactions.bad.al`. +See sample: `al-methods-limited-during-write-transactions.bad.al`. ## Source From 9e226279d8436e217dadb321c6e0566124935b07 Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Mon, 7 Sep 2026 23:15:43 +0200 Subject: [PATCH 5/8] Trim keywords to 10 per validator guidance --- .../performance/al-methods-limited-during-write-transactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md index c22959ad..d05898d0 100644 --- a/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md +++ b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md @@ -1,7 +1,7 @@ --- bc-version: [all] domain: performance -keywords: [limited-during-write-transactions, write-transaction, runmodal, form-runmodal, page-runmodal, report-runmodal, xmlport-runmodal, codeunit-run, commit, requestpage, runtime-error] +keywords: [limited-during-write-transactions, write-transaction, runmodal, form-runmodal, page-runmodal, report-runmodal, xmlport-runmodal, codeunit-run, commit, requestpage] technologies: [al] countries: [w1] application-area: [all] From 556f8281faa984adc98fee1757b146aa751e1c39 Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Tue, 8 Sep 2026 06:42:54 +0200 Subject: [PATCH 6/8] Wire the new article into al-performance-review.md Adds Page.RunModal / Report.RunModal / XmlPort.RunModal / UseRequestPage to the extracted-token list and one deterministic worklist cue with exclusions, so the article is selected from the RunModal call itself rather than only via a co-located Commit/Modify token. Codeunit.Run in that position is routed to its existing owner article. Co-Authored-By: Claude Fable 5.1 --- microsoft/skills/review/al-performance-review.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/microsoft/skills/review/al-performance-review.md b/microsoft/skills/review/al-performance-review.md index 7829d705..0eeefd32 100644 --- a/microsoft/skills/review/al-performance-review.md +++ b/microsoft/skills/review/al-performance-review.md @@ -39,7 +39,7 @@ Narrow the relevant files to the subset that applies to the changes under review - The changed AL object names and types — especially tables, pages with SourceTable bindings, reports, queries, and codeunits performing record iteration. - The changed procedures and triggers, weighted toward those that perform loops, Find/FindSet/FindFirst calls, CalcFields, SetAutoCalcFields, CalcSums, FlowField access, Commit calls, checkpoint helpers, record copying, RecordRef conversion, Modify/Delete calls, or cross-table navigation. -- Tokens extracted from the diff that relate to data access, hot-path costs, and background scheduling (`SetRange`, `SetFilter`, `SetLoadFields`, `SetCurrentKey`, `FindSet`, `ReadIsolation`, `LockTable`, `ModifyAll`, `DeleteAll`, `Modify`, `Delete`, `Commit`, `checkpoint`, `Copy`, `RecordRef`, `GetTable`, `TextBuilder`, `Dictionary`, `temporary`, `repeat`, `until`, `CalcFields`, `SetAutoCalcFields`, `CalcSums`, `FlowField`, `Visible`, `Job Queue Entry`, `Job Queue Category Code`, `Confirm`, `RunModal`, `GuiAllowed`, `TryFunction`, `Codeunit.Run`, `HttpClient`, `Status`, `On Hold`, `stop request`, `TaskScheduler.CreateTask`, `TaskScheduler.TaskExists`). +- Tokens extracted from the diff that relate to data access, hot-path costs, and background scheduling (`SetRange`, `SetFilter`, `SetLoadFields`, `SetCurrentKey`, `FindSet`, `ReadIsolation`, `LockTable`, `ModifyAll`, `DeleteAll`, `Modify`, `Delete`, `Commit`, `checkpoint`, `Copy`, `RecordRef`, `GetTable`, `TextBuilder`, `Dictionary`, `temporary`, `repeat`, `until`, `CalcFields`, `SetAutoCalcFields`, `CalcSums`, `FlowField`, `Visible`, `Job Queue Entry`, `Job Queue Category Code`, `Confirm`, `RunModal`, `GuiAllowed`, `TryFunction`, `Codeunit.Run`, `HttpClient`, `Status`, `On Hold`, `stop request`, `TaskScheduler.CreateTask`, `TaskScheduler.TaskExists`, `Page.RunModal`, `Report.RunModal`, `Xmlport.Run`, `UseRequestPage`). A file enters the candidate worklist when its `keywords` intersect the extracted tokens or its topic (derived from the index entry's `path`, `title`, and `description`) matches a changed object type. Read an article's full file — its `## Best Practice` / `## Anti Pattern` bodies — only after it makes the worklist; candidate selection uses the index alone. @@ -58,6 +58,7 @@ Apply these targeted cues even when simple token overlap would rank the article - Worklist `job-queue-on-hold-does-not-stop-running-work.md` when a running job queue handler polls the entry's `Status` or `On Hold` value as a cancellation signal. Exclude application-owned stop requests that are checked before every bounded unit of work, including the first, when completed work and its checkpoint remain consistent and resume logic clears the request. - Worklist `job-queue-category-code-serializes-conflicting-jobs.md` when two or more job queue entries in the same company are shown by the changed context to require mutual exclusion but have empty or different Job Queue Category Codes. Do not infer a conflict merely because jobs touch the same tables, and do not recommend a category to coordinate across companies, environments, or workers outside the job queue dispatcher. - Worklist `store-scheduled-task-id-to-avoid-duplicate-tasks.md` when `TaskScheduler.CreateTask` runs from initialization, login, setup, or another repeatable path without persisting its returned GUID and checking it with `TaskScheduler.TaskExists` before creating a replacement. Exclude one-shot creation and correctly persisted check-before-create flows; concurrent callers still require serialization around that sequence. +- Worklist `al-methods-limited-during-write-transactions.md` when `Page.RunModal` follows an `Insert`, `Modify`, or `Delete` in the same trigger or procedure with no intervening `Commit`; or when `Report.RunModal` without `false` as its `RequestWindow` argument and without `UseRequestPage(false)` follows one; or when `Xmlport.Run` without `false` as its `RequestWindow` argument and without the `UseRequestPage = false` object property follows one. Do not worklist it from a call that precedes every write, from a report run with its request page suppressed via `UseRequestPage(false)`/`RunModal(...,false)`, or from an XMLport run with its request page suppressed via the `RequestWindow` argument or the `UseRequestPage` property. A `Codeunit.Run` whose return value is used in that position belongs to `codeunit-run-requires-prior-commit-inside-transaction.md`. These targeted inclusions and exclusions override generic token overlap. Do not retain an excluded article solely because the diff contains one of its keywords. From fb896e9734568d5208a41a293221af854f60a0c4 Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Mon, 21 Sep 2026 22:01:07 +0200 Subject: [PATCH 7/8] Correct XmlPort.RunModal to Xmlport.Run; fix READ-convention sample links XmlPort has no RunModal method (static or instance) - Microsoft Learn confirms only Xmlport.Run(Integer [, Boolean RequestWindow] [, Boolean] [, var Record]). Replaces the invented API with the real one throughout the article, worklist cue, and token list, and explains the platform error message's own "XmlPort.RunModal" wording as the same kind of legacy phrasing already noted for Form.RunModal/RequestForm. Also corrects UseRequestPage(false): that's a Report instance method only, not applicable to XMLport, which uses the UseRequestPage = false object property or Run's RequestWindow argument instead. Fixes the two sample references to use the READ-convention markdown link form (Test-KnowledgeIndex.ps1's Knowledge-Retrieval.ps1 check was failing on plain backtick text). Rebased onto upstream/main to resolve conflicts with #148's job-queue additions to al-performance-review.md - both sets of worklist tokens and cues are retained. --- ...al-methods-limited-during-write-transactions.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md index d05898d0..49f3cf08 100644 --- a/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md +++ b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md @@ -1,7 +1,7 @@ --- bc-version: [all] domain: performance -keywords: [limited-during-write-transactions, write-transaction, runmodal, form-runmodal, page-runmodal, report-runmodal, xmlport-runmodal, codeunit-run, commit, requestpage] +keywords: [limited-during-write-transactions, write-transaction, runmodal, form-runmodal, page-runmodal, report-runmodal, xmlport-run, codeunit-run, commit, requestpage] technologies: [al] countries: [w1] application-area: [all] @@ -15,30 +15,32 @@ Once AL code has written to the database in the current transaction — an `Inse - `Page.RunModal` — not allowed in a write transaction, under any circumstances. - `Report.RunModal` — allowed only if the request page is suppressed: `Report.RunModal(ReportId, false)` (the second argument is `RequestWindow`), or `UseRequestPage(false)` on a report instance. With a request page it fails. -- `XmlPort.RunModal` — same rule: allowed only if the request page is suppressed, `XmlPort.RunModal(..., false)`. With a request page it fails. +- `Xmlport.Run` — same rule when it would show a request page: allowed only if the request page is suppressed, `Xmlport.Run(XmlPortId, false)` (the second argument is `RequestWindow`) or the `UseRequestPage = false;` object property. With a request page shown it fails. There is no `XmlPort.RunModal` method — see the note on the platform's error text below. - `Codeunit.Run` — allowed only if its Boolean return value is not used. `OK := Codeunit.Run()` and `if Codeunit.Run() then` fail, because that form commits — see `codeunit-run-requires-prior-commit-inside-transaction.md`. This is a runtime error, not a compiler diagnostic: the code builds, and the first execution that reaches the call with an open write transaction dies. The guard keys on transaction state alone, not on any relation between what was written and what is opened: an `Item.Insert()` followed by `Page.RunModal(Page::"Customer Card")` — an unrelated table — fails on the `RunModal` line, and because the error stops the transaction, the insert rolls back with it. -The platform's message (Business Central 26, reproduced 2026-09-07) reads: "The following AL methods are limited during write transactions because one or more tables will be locked: Form.RunModal, Codeunit.Run, Report.RunModal, XmlPort.RunModal. Form.RunModal is not allowed in write transactions. Codeunit.Run is allowed in write transactions only if the return value is not used. For example, 'OK := Codeunit.Run()' is not allowed. Report.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'Report.RunModal(...,false)' is allowed. XmlPort.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'XmlPort.RunModal(...,false)' is allowed. Use the commit method to save the changes before this call, or structure the code differently." The message still uses the legacy names `Form.RunModal` and `RequestForm` even though the AL method is `Page.RunModal` and the report parameter is `RequestWindow`; older versions said "C/AL functions" instead of "AL methods" (microsoft/AL#5452, 2019). The behavior is unchanged across versions. +The platform's message (Business Central 26, reproduced 2026-09-07) reads: "The following AL methods are limited during write transactions because one or more tables will be locked: Form.RunModal, Codeunit.Run, Report.RunModal, XmlPort.RunModal. Form.RunModal is not allowed in write transactions. Codeunit.Run is allowed in write transactions only if the return value is not used. For example, 'OK := Codeunit.Run()' is not allowed. Report.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'Report.RunModal(...,false)' is allowed. XmlPort.RunModal is allowed in write transactions only if 'RequestForm = false'. For example, 'XmlPort.RunModal(...,false)' is allowed. Use the commit method to save the changes before this call, or structure the code differently." The message still uses the legacy names `Form.RunModal` and `RequestForm` even though the AL method is `Page.RunModal` and the report parameter is `RequestWindow`; older versions said "C/AL functions" instead of "AL methods" (microsoft/AL#5452, 2019). The message also names `XmlPort.RunModal`, which is legacy phrasing too — there is no such AL method; the actual API the guard applies to is `Xmlport.Run`, and the message's `RequestForm = false` condition corresponds to `Xmlport.Run`'s `RequestWindow` argument or the `UseRequestPage` property. The behavior is unchanged across versions. The reason is the same one behind `avoid-user-prompts-inside-transactions.md`: a modal object waits for the user, and the platform will not let a write transaction — and every lock it holds — sit open for as long as that takes. The difference is enforcement. `Confirm` and `StrMenu` are *allowed* inside a write transaction and silently hold the locks; `RunModal` is *refused*. Both point at the same design fix. ## Best Practice -Sequence the work so the modal interaction happens before the write phase: run the lookup or dialog page first, then perform the writes the user's choice requires, and let the transaction end. When a modal object genuinely must follow a write, `Commit()` first — but only when the state written so far is complete and safe to persist on its own, because that Commit is a real transaction boundary, not a formality. Microsoft's own Base Application follows exactly this pattern where the preceding state is final (`ActivityLog.Table.al` commits the log entry before `Page.RunModal(Page::"Activity Log", Rec)`; `DocumentSendingProfile.Table.al` commits before `Page.RunModal(Page::"Select Sending Options", …)`). For a report or XMLport, suppressing the request page (`UseRequestPage(false)`) is a legitimate way to run it inside a write transaction when no user input is needed. `Database.IsInWriteTransaction()` (runtime 11.0+) lets library code that cannot control its caller detect the state, with the same caveat as the Codeunit.Run article: branching production flow on it usually signals unclear transaction ownership. +Sequence the work so the modal interaction happens before the write phase: run the lookup or dialog page first, then perform the writes the user's choice requires, and let the transaction end. When a modal object genuinely must follow a write, `Commit()` first — but only when the state written so far is complete and safe to persist on its own, because that Commit is a real transaction boundary, not a formality. Microsoft's own Base Application follows exactly this pattern where the preceding state is final (`ActivityLog.Table.al` commits the log entry before `Page.RunModal(Page::"Activity Log", Rec)`; `DocumentSendingProfile.Table.al` commits before `Page.RunModal(Page::"Select Sending Options", …)`). For a report, suppressing the request page — `Report.UseRequestPage(false)` on a report instance, or `false` as the `RequestWindow` argument to `Run`/`RunModal` — is a legitimate way to run it inside a write transaction when no user input is needed. For an XMLport, the equivalent is `false` as the `RequestWindow` argument to `Xmlport.Run`, or the `UseRequestPage = false;` object property; XMLports have no instance `UseRequestPage` method. `Database.IsInWriteTransaction()` (runtime 11.0+) lets library code that cannot control its caller detect the state, with the same caveat as the Codeunit.Run article: branching production flow on it usually signals unclear transaction ownership. -See sample: `al-methods-limited-during-write-transactions.good.al`. +See sample: [`al-methods-limited-during-write-transactions.good.al`](al-methods-limited-during-write-transactions.good.al). ## Anti Pattern Writing to the database and then calling `Page.RunModal` (or a report/XMLport with its request page) in the same trigger — the first production run hits the runtime error. The reflexive fixes are worse than the error: dropping in `Commit()` to silence it persists a half-finished state that can no longer roll back with the rest of the operation, and swapping the page for a `Confirm` or `StrMenu` to "avoid the error" trades a loud failure for the silent lock-holding that `avoid-user-prompts-inside-transactions.md` warns about. -See sample: `al-methods-limited-during-write-transactions.bad.al`. +See sample: [`al-methods-limited-during-write-transactions.bad.al`](al-methods-limited-during-write-transactions.bad.al). ## Source - Microsoft Learn, `Codeunit.Run` transaction semantics ("If you're already in a transaction you must commit first before calling Codeunit.Run"): https://learn.microsoft.com/dynamics365/business-central/dev-itpro/developer/methods-auto/codeunit/codeunit-run-method +- Microsoft Learn, `Xmlport.Run(Integer [, Boolean] [, Boolean] [, var Record])` (the `RequestWindow` argument; confirms the XMLport data type has no `RunModal` method, static or instance): https://learn.microsoft.com/dynamics365/business-central/dev-itpro/developer/methods-auto/xmlport/xmlport-run-method +- Microsoft Learn, `UseRequestPage` property ("Applies to: Xml Port, Report" — an object property, not an XMLport instance method; the instance method of the same name exists only on `Report`): https://learn.microsoft.com/dynamics365/business-central/dev-itpro/developer/properties/devenv-userequestpage-property - microsoft/AL issue #5452 (verbatim English error text, reproduced on "any current version of Business Central", 2019-11-13): https://github.com/microsoft/AL/issues/5452 - Reproduced 2026-09-07 on Business Central 26 (runtime error dialog, English and Danish clients): a page `OnAction` doing `Item.Insert()` then `Page.RunModal(Page::"Customer Card")` fails with the text quoted in the Description, the AL call stack pointing at the `RunModal` line, and the dialog stating that the transaction was stopped. - Microsoft Base Application (BCApps, W1): the `Commit(); … Page.RunModal(…)` pattern in `Modules/System/Logging/ActivityLog.Table.al`, `Foundation/Reporting/DocumentSendingProfile.Table.al`, `Bank/Setup/PaymentServiceSetup.Table.al`, and others; BCApps test suites annotate the same guard as "COMMIT is required for Write Transaction Error" (`Tests/General Journal/ERMTestMultipleGenJnlLines.Codeunit.al`). From 697c5aec7972c82416b6c5d523daff51aebb4681 Mon Sep 17 00:00:00 2001 From: Michael Dieringer <65093775+MichaelDieringer@users.noreply.github.com> Date: Tue, 22 Sep 2026 14:27:32 +0200 Subject: [PATCH 8/8] Add Report.Run alongside Report.RunModal to the write-transaction guard routing al-performance-review.md's tokens/cues only recognized Report.RunModal, so a failing Modify(); Report.Run(..., true, ...) path was never worklisted even though Report.Run shares the exact same RequestWindow- blocking-dialog mechanism as Report.RunModal (they differ only in whether the report instance is cleared afterward). Added Report.Run to the token list and the targeted cue, with the same request-page- suppressed exclusion, and extended the knowledge article's Description bullet to name both methods explicitly instead of only RunModal. --- .../al-methods-limited-during-write-transactions.md | 4 ++-- microsoft/skills/review/al-performance-review.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md index 49f3cf08..2bbedb35 100644 --- a/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md +++ b/microsoft/knowledge/performance/al-methods-limited-during-write-transactions.md @@ -1,7 +1,7 @@ --- bc-version: [all] domain: performance -keywords: [limited-during-write-transactions, write-transaction, runmodal, form-runmodal, page-runmodal, report-runmodal, xmlport-run, codeunit-run, commit, requestpage] +keywords: [limited-during-write-transactions, write-transaction, runmodal, report-run, page-runmodal, report-runmodal, xmlport-run, codeunit-run, commit, requestpage] technologies: [al] countries: [w1] application-area: [all] @@ -14,7 +14,7 @@ application-area: [all] Once AL code has written to the database in the current transaction — an `Insert`, `Modify`, or `Delete` with no `Commit` since — the platform restricts four methods until that transaction is committed. The exact conditions, as enforced: - `Page.RunModal` — not allowed in a write transaction, under any circumstances. -- `Report.RunModal` — allowed only if the request page is suppressed: `Report.RunModal(ReportId, false)` (the second argument is `RequestWindow`), or `UseRequestPage(false)` on a report instance. With a request page it fails. +- `Report.RunModal` and `Report.Run` — both allowed only if the request page is suppressed: `Report.RunModal(ReportId, false)` / `Report.Run(ReportId, false)` (the second argument is `RequestWindow` in both), or `UseRequestPage(false)` on a report instance. With a request page shown, either fails identically — `Run` and `RunModal` differ only in whether the report instance is cleared afterward, not in this guard. - `Xmlport.Run` — same rule when it would show a request page: allowed only if the request page is suppressed, `Xmlport.Run(XmlPortId, false)` (the second argument is `RequestWindow`) or the `UseRequestPage = false;` object property. With a request page shown it fails. There is no `XmlPort.RunModal` method — see the note on the platform's error text below. - `Codeunit.Run` — allowed only if its Boolean return value is not used. `OK := Codeunit.Run()` and `if Codeunit.Run() then` fail, because that form commits — see `codeunit-run-requires-prior-commit-inside-transaction.md`. diff --git a/microsoft/skills/review/al-performance-review.md b/microsoft/skills/review/al-performance-review.md index 0eeefd32..5478b859 100644 --- a/microsoft/skills/review/al-performance-review.md +++ b/microsoft/skills/review/al-performance-review.md @@ -39,7 +39,7 @@ Narrow the relevant files to the subset that applies to the changes under review - The changed AL object names and types — especially tables, pages with SourceTable bindings, reports, queries, and codeunits performing record iteration. - The changed procedures and triggers, weighted toward those that perform loops, Find/FindSet/FindFirst calls, CalcFields, SetAutoCalcFields, CalcSums, FlowField access, Commit calls, checkpoint helpers, record copying, RecordRef conversion, Modify/Delete calls, or cross-table navigation. -- Tokens extracted from the diff that relate to data access, hot-path costs, and background scheduling (`SetRange`, `SetFilter`, `SetLoadFields`, `SetCurrentKey`, `FindSet`, `ReadIsolation`, `LockTable`, `ModifyAll`, `DeleteAll`, `Modify`, `Delete`, `Commit`, `checkpoint`, `Copy`, `RecordRef`, `GetTable`, `TextBuilder`, `Dictionary`, `temporary`, `repeat`, `until`, `CalcFields`, `SetAutoCalcFields`, `CalcSums`, `FlowField`, `Visible`, `Job Queue Entry`, `Job Queue Category Code`, `Confirm`, `RunModal`, `GuiAllowed`, `TryFunction`, `Codeunit.Run`, `HttpClient`, `Status`, `On Hold`, `stop request`, `TaskScheduler.CreateTask`, `TaskScheduler.TaskExists`, `Page.RunModal`, `Report.RunModal`, `Xmlport.Run`, `UseRequestPage`). +- Tokens extracted from the diff that relate to data access, hot-path costs, and background scheduling (`SetRange`, `SetFilter`, `SetLoadFields`, `SetCurrentKey`, `FindSet`, `ReadIsolation`, `LockTable`, `ModifyAll`, `DeleteAll`, `Modify`, `Delete`, `Commit`, `checkpoint`, `Copy`, `RecordRef`, `GetTable`, `TextBuilder`, `Dictionary`, `temporary`, `repeat`, `until`, `CalcFields`, `SetAutoCalcFields`, `CalcSums`, `FlowField`, `Visible`, `Job Queue Entry`, `Job Queue Category Code`, `Confirm`, `RunModal`, `GuiAllowed`, `TryFunction`, `Codeunit.Run`, `HttpClient`, `Status`, `On Hold`, `stop request`, `TaskScheduler.CreateTask`, `TaskScheduler.TaskExists`, `Page.RunModal`, `Report.RunModal`, `Report.Run`, `Xmlport.Run`, `UseRequestPage`). A file enters the candidate worklist when its `keywords` intersect the extracted tokens or its topic (derived from the index entry's `path`, `title`, and `description`) matches a changed object type. Read an article's full file — its `## Best Practice` / `## Anti Pattern` bodies — only after it makes the worklist; candidate selection uses the index alone. @@ -58,7 +58,7 @@ Apply these targeted cues even when simple token overlap would rank the article - Worklist `job-queue-on-hold-does-not-stop-running-work.md` when a running job queue handler polls the entry's `Status` or `On Hold` value as a cancellation signal. Exclude application-owned stop requests that are checked before every bounded unit of work, including the first, when completed work and its checkpoint remain consistent and resume logic clears the request. - Worklist `job-queue-category-code-serializes-conflicting-jobs.md` when two or more job queue entries in the same company are shown by the changed context to require mutual exclusion but have empty or different Job Queue Category Codes. Do not infer a conflict merely because jobs touch the same tables, and do not recommend a category to coordinate across companies, environments, or workers outside the job queue dispatcher. - Worklist `store-scheduled-task-id-to-avoid-duplicate-tasks.md` when `TaskScheduler.CreateTask` runs from initialization, login, setup, or another repeatable path without persisting its returned GUID and checking it with `TaskScheduler.TaskExists` before creating a replacement. Exclude one-shot creation and correctly persisted check-before-create flows; concurrent callers still require serialization around that sequence. -- Worklist `al-methods-limited-during-write-transactions.md` when `Page.RunModal` follows an `Insert`, `Modify`, or `Delete` in the same trigger or procedure with no intervening `Commit`; or when `Report.RunModal` without `false` as its `RequestWindow` argument and without `UseRequestPage(false)` follows one; or when `Xmlport.Run` without `false` as its `RequestWindow` argument and without the `UseRequestPage = false` object property follows one. Do not worklist it from a call that precedes every write, from a report run with its request page suppressed via `UseRequestPage(false)`/`RunModal(...,false)`, or from an XMLport run with its request page suppressed via the `RequestWindow` argument or the `UseRequestPage` property. A `Codeunit.Run` whose return value is used in that position belongs to `codeunit-run-requires-prior-commit-inside-transaction.md`. +- Worklist `al-methods-limited-during-write-transactions.md` when `Page.RunModal` follows an `Insert`, `Modify`, or `Delete` in the same trigger or procedure with no intervening `Commit`; or when `Report.RunModal`/`Report.Run` without `false` as its `RequestWindow` argument and without `UseRequestPage(false)` follows one; or when `Xmlport.Run` without `false` as its `RequestWindow` argument and without the `UseRequestPage = false` object property follows one. Do not worklist it from a call that precedes every write, from a report run with its request page suppressed via `UseRequestPage(false)`/`Run(...,false)`/`RunModal(...,false)`, or from an XMLport run with its request page suppressed via the `RequestWindow` argument or the `UseRequestPage` property. A `Codeunit.Run` whose return value is used in that position belongs to `codeunit-run-requires-prior-commit-inside-transaction.md`. These targeted inclusions and exclusions override generic token overlap. Do not retain an excluded article solely because the diff contains one of its keywords.