diff --git a/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.bad.al b/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.bad.al index 674801c..6fc5b06 100644 --- a/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.bad.al +++ b/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.bad.al @@ -1,13 +1,12 @@ codeunit 50308 "ErrorInfo Privacy Bad" { - procedure RaiseSynchronizationError(Customer: Record Customer; ResponseBody: Text) + procedure RaiseSynchronizationError(Customer: Record Customer) var FailureInfo: ErrorInfo; begin FailureInfo.Message := StrSubstNo('Synchronization failed for %1.', Customer."E-Mail"); FailureInfo.DataClassification := DataClassification::SystemMetadata; FailureInfo.ErrorType := ErrorType::Internal; - FailureInfo.DetailedMessage := ResponseBody; Error(FailureInfo); end; } diff --git a/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.good.al b/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.good.al index dd91df9..1da3c1f 100644 --- a/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.good.al +++ b/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.good.al @@ -7,11 +7,9 @@ codeunit 50307 "ErrorInfo Privacy Good" FailureInfo.Message := SynchronizationFailedErr; FailureInfo.DataClassification := DataClassification::SystemMetadata; FailureInfo.ErrorType := ErrorType::Client; - FailureInfo.DetailedMessage := RetryDiagnosticsTxt; Error(FailureInfo); end; var - RetryDiagnosticsTxt: Label 'The remote service rejected the request. Review the integration telemetry event.'; SynchronizationFailedErr: Label 'The synchronization could not be completed.'; } diff --git a/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.md b/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.md index 69e292c..fc94c61 100644 --- a/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.md +++ b/microsoft/knowledge/privacy/errorinfo-telemetry-classification-and-errortype.md @@ -1,7 +1,7 @@ --- -bc-version: [19..] +bc-version: [14..] domain: privacy -keywords: [errorinfo, message, dataclassification, errortype, detailedmessage, copy-details, telemetry] +keywords: [errorinfo, errorinfo-message, errorinfo-dataclassification, errorinfo-errortype, errorinfo-detailedmessage, copy-details, telemetry] technologies: [al] countries: [w1] application-area: [all] @@ -11,16 +11,16 @@ application-area: [all] ## Description -`ErrorInfo.Message` is sent to telemetry; with `ErrorType::Client` it is also the primary client message, while `ErrorType::Internal` replaces it in the client with a generic message but still sends the specified text to telemetry. `DataClassification` classifies the content in `Message`; it does not make incorrectly classified personal data safe. `DetailedMessage`, available from BC 19, is omitted from the primary message but is included in the error dialog's **Copy details** content. +From BC 14, `ErrorInfo.Message` is sent to telemetry; with `ErrorType::Client` it is also the primary client message, while `ErrorType::Internal` replaces it in the client with a generic message but still sends the specified text to telemetry. `DataClassification` classifies the content in `Message`; it does not make incorrectly classified personal data safe. Starting in BC 19, `DetailedMessage` is omitted from the primary message but is included in the error dialog's **Copy details** content. ## Best Practice -Keep `Message` stable and classify its actual content. Choose `ErrorType` for client usability, not as a telemetry privacy boundary. Put only support-safe technical context in `DetailedMessage`, because a user can copy it from the dialog. +Keep `Message` stable and classify its actual content. Choose `ErrorType` for client usability, not as a telemetry privacy boundary. On BC 19 and later, put only support-safe technical context in `DetailedMessage`, because a user can copy it from the dialog. See sample: `errorinfo-telemetry-classification-and-errortype.good.al`. ## Anti Pattern -Marking a dynamic customer-bearing `Message` as `SystemMetadata`, assuming `ErrorType::Internal` keeps it out of telemetry, or placing secrets and personal data in `DetailedMessage` because it is not the primary dialog text. +Marking a dynamic customer-bearing `Message` as `SystemMetadata`, or assuming `ErrorType::Internal` keeps it out of telemetry. On BC 19 and later, the same anti-pattern includes placing secrets or personal data in `DetailedMessage` because it is not the primary dialog text. See sample: `errorinfo-telemetry-classification-and-errortype.bad.al`. diff --git a/microsoft/skills/review/al-privacy-review.md b/microsoft/skills/review/al-privacy-review.md index 646f7ea..8a684c1 100644 --- a/microsoft/skills/review/al-privacy-review.md +++ b/microsoft/skills/review/al-privacy-review.md @@ -39,8 +39,9 @@ Narrow the relevant files to the subset that applies to the changes under review - The changed AL object names and types — especially tables and tableextensions (for `DataClassification` on fields), codeunits that call `Error`, `Session.LogMessage`, or `FeatureTelemetry`, codeunits performing outgoing HTTP requests with customer data, migration codeunits, and objects reading or writing `IsolatedStorage`. - The changed procedures and triggers, weighted toward those that call `Error`, construct `ErrorInfo`, call `Session.LogMessage`, `StrSubstNo`, `GetLastErrorText`/`GetLastErrorCallStack`, `FeatureTelemetry.LogUsage`/`LogUptake`/`LogError`, `HttpClient.Post`/`Get`, `IsolatedStorage.Set`/`SetEncrypted`/`Get`, or `PrivacyNotice.GetPrivacyNoticeApprovalState`. -- Tokens extracted from the diff that relate to privacy (`DataClassification`, `CustomerContent`, `EndUserIdentifiableInformation`, `EndUserPseudonymousIdentifiers`, `SystemMetadata`, `ToBeClassified`, `PrivacyNotice`, `ErrorInfo`, `Message`, `DetailedMessage`, `ErrorType`, `Internal`, `Client`, `GetLastErrorText`, `GetLastErrorCallStack`, `TelemetryScope`, `FeatureTelemetry`, `CustomDimensions`, `LogUsage`, `LogUptake`, `LogError`, `ErrorText`, `ErrorCallStack`, `alErrorText`, `alErrorCallStack`, `HybridSL`, `HybridGP`, `HybridBC`). -- Worklist ErrorInfo privacy guidance when any of `Message`, `DataClassification`, `ErrorType`, or `DetailedMessage` changes. For every `FeatureTelemetry.LogError`, inspect the dedicated error text and call-stack arguments in addition to explicit custom dimensions. +- Tokens extracted from the diff that relate to privacy (`DataClassification`, `CustomerContent`, `EndUserIdentifiableInformation`, `EndUserPseudonymousIdentifiers`, `SystemMetadata`, `ToBeClassified`, `PrivacyNotice`, `ErrorInfo`, `GetLastErrorText`, `GetLastErrorCallStack`, `TelemetryScope`, `FeatureTelemetry`, `CustomDimensions`, `LogUsage`, `LogUptake`, `LogError`, `ErrorText`, `ErrorCallStack`, `alErrorText`, `alErrorCallStack`, `HybridSL`, `HybridGP`, `HybridBC`). +- When symbol resolution identifies a member-access receiver as an `ErrorInfo` variable, normalize changed `.Message`, `.DataClassification`, `.ErrorType`, and `.DetailedMessage` accesses to `errorinfo-message`, `errorinfo-dataclassification`, `errorinfo-errortype`, and `errorinfo-detailedmessage` retrieval tokens. Do not emit those tokens for `Message(...)` dialog calls, table or table-field `DataClassification` properties, or similarly named members on other types. Resolve the receiver's declaration from the containing object when it is outside the changed hunk. +- Worklist ErrorInfo privacy guidance only from those typed `ErrorInfo` member tokens or from construction of an `ErrorInfo` value. For every `FeatureTelemetry.LogError`, inspect the dedicated error text and call-stack arguments in addition to explicit custom dimensions. 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. diff --git a/microsoft/skills/review/al-upgrade-review.md b/microsoft/skills/review/al-upgrade-review.md index b298621..97ce294 100644 --- a/microsoft/skills/review/al-upgrade-review.md +++ b/microsoft/skills/review/al-upgrade-review.md @@ -40,7 +40,9 @@ Narrow the relevant files to the subset that applies to the changes under review - The changed AL object names and types — especially codeunits with `Subtype = Upgrade` or `Subtype = Install`, tables and tableextensions adding or changing fields, enums and enumextensions, and objects under `Hybrid*`/`Migration`/`Upgrade` namespaces. - The changed triggers and procedures, weighted toward `OnCheckPreconditionsPerCompany`/`PerDatabase`, `OnUpgradePerCompany`/`PerDatabase`, `OnValidateUpgradePerCompany`/`PerDatabase`, `OnInstallAppPerCompany`/`PerDatabase`, and the `OnGetPerCompanyUpgradeTags`/`OnGetPerDatabaseUpgradeTags` subscribers. - Tokens extracted from the diff that relate to upgrade concerns (`Subtype = Upgrade`, `Subtype = Install`, `Upgrade Tag`, `HasUpgradeTag`, `SetUpgradeTag`, `OnCheckPreconditions`, `OnUpgrade`, `OnValidateUpgrade`, `OnInstallApp`, `DataTransfer`, `CopyFields`, `Insert`, `Modify`, `Delete`, `Rename`, `InitValue`, `ObsoleteState`, `ObsoleteReason`, `ObsoleteTag`, `DataVersion`, `ExecutionContext`, `PrimaryKey`, `key(`, `field(`, `value(`, `enum`, `enumextension`, `HybridSL`, `HybridGP`, `HybridBC`, `HybridBaseDeployment`). -- Worklist the check-only rule when precondition or validation triggers contain writes, and the install-versus-upgrade rule when migration helpers are reachable only from an install codeunit. +- For each `OnCheckPreconditions...` and `OnValidateUpgrade...` trigger, trace resolved calls through reachable local or internal helpers. Worklist the check-only rule when the trigger or any transitive callee performs `Insert`, `Modify`, `ModifyAll`, `Delete`, `DeleteAll`, `Rename`, `DataTransfer`, or another database write. Also perform the reverse check when a PR changes a writing helper body: worklist the rule when an unchanged check or validation trigger can reach that helper. +- Treat a direct write or a fully resolved call chain as high-confidence evidence. When cross-object dispatch, unavailable declarations, or an incomplete call graph prevents proving the complete chain, cap confidence at `medium`, name the unresolved edge in the finding, and do not claim a violation without a resolved path from a check or validation trigger to a write. +- Worklist the install-versus-upgrade rule when migration helpers are reachable only from an install codeunit. 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. When the diff contains no upgrade-related changes by any of the above signals, return `outcome: "not-applicable"` without evaluating files.