From c995f81717a013641d202f3387946026555c2716 Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Sat, 12 Sep 2026 15:23:36 +0200 Subject: [PATCH 1/2] docs(PC0029): describe global variable tracing Update the rule description to mention object-scope variable tracking and add an exception entry for var parameter and return value flows that are not traced back to callers. Co-Authored-By: Claude Fable 5.1 --- content/docs/analyzers/PlatformCop/PC0029.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/docs/analyzers/PlatformCop/PC0029.md b/content/docs/analyzers/PlatformCop/PC0029.md index eec9d34..7b113df 100644 --- a/content/docs/analyzers/PlatformCop/PC0029.md +++ b/content/docs/analyzers/PlatformCop/PC0029.md @@ -12,7 +12,7 @@ linkTitle = 'PC0029' When a new record needs a GUID primary key, the natural reach is `CreateGuid()`. Random GUIDs scatter values across the SQL index B-tree, causing page splits on every insert. At scale — bulk imports, high-throughput journal posting — this fragmentation degrades insert, read, and update performance by 20–40%. -This rule tracks the flow of `CreateGuid()` values through variable assignments and procedure calls (within the same module) to determine whether the generated GUID ultimately lands in a key field. Replace `CreateGuid()` with `Guid.CreateSequentialGuid()`, which produces partially-sequential values that keep index inserts append-only. +This rule tracks the flow of `CreateGuid()` values through variable assignments (local and object-scope variables of the same object) and procedure calls (within the same module) to determine whether the generated GUID ultimately lands in a key field. Replace `CreateGuid()` with `Guid.CreateSequentialGuid()`, which produces partially-sequential values that keep index inserts append-only. ### Example @@ -80,6 +80,7 @@ The rule does not flag the following scenarios: - `CreateGuid()` assigned to fields in **temporary** tables (no SQL backing, so no index fragmentation). - `CreateGuid()` passed as an argument to **event publishers** (idiomatic AL pattern for correlation IDs). - `CreateGuid()` passed to procedures in **external dependencies** where the source code is not available. +- GUIDs returned from, or written to `var` parameters of, helper procedures are not traced back to the caller. If you intentionally need a random GUID in a key field — for example, to prevent callers from guessing adjacent values in a public API — suppress the diagnostic with a pragma: From 169155f8c36060587015209518e21cc989d8caaf Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Sun, 13 Sep 2026 08:36:00 +0200 Subject: [PATCH 2/2] docs(PC0029): implicit primary key and TableNo OnRun receivers Add a paragraph after the flow-tracking description noting that the key check covers the synthesized primary key (tables without a keys section) and that CreateGuid() values are recognised through every receiver form: named variables, Rec on tables/pages/request pages/TableNo codeunits, bare field access in tables and table extensions, and this. Co-Authored-By: Claude Fable 5.1 --- content/docs/analyzers/PlatformCop/PC0029.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/content/docs/analyzers/PlatformCop/PC0029.md b/content/docs/analyzers/PlatformCop/PC0029.md index 7b113df..9bc4709 100644 --- a/content/docs/analyzers/PlatformCop/PC0029.md +++ b/content/docs/analyzers/PlatformCop/PC0029.md @@ -14,6 +14,8 @@ When a new record needs a GUID primary key, the natural reach is `CreateGuid()`. This rule tracks the flow of `CreateGuid()` values through variable assignments (local and object-scope variables of the same object) and procedure calls (within the same module) to determine whether the generated GUID ultimately lands in a key field. Replace `CreateGuid()` with `Guid.CreateSequentialGuid()`, which produces partially-sequential values that keep index inserts append-only. +The key check includes the implicit primary key of a table declared without a `keys` section, and the value is recognised however the record is reached — a named variable, `Rec` (tables, pages, request pages, and the `OnRun` trigger of a codeunit with `TableNo`), bare field access inside tables and table extensions, and `this`. + ### Example {{< highlight al "hl_lines=7" >}}