mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-10-06 15:16:56 +01:00
Merge branch 'main' of https://github.com/demiliani/BCQuality into appsource
# Conflicts: # microsoft/skills/review/al-appsource-review.md
This commit is contained in:
commit
a300675320
341 changed files with 3900 additions and 1896 deletions
|
|
@ -17,13 +17,13 @@ An agent is a user, but it cannot configure users or other agents, and it cannot
|
|||
|
||||
Document that intersection. Give the agent only the table and page rights its tasks need. Do not add user-setup or permission-assignment pages to the agent profile or permission sets; those operations will fail by design.
|
||||
|
||||
See sample: `agent-permissions-intersect-with-assigner.good.al`.
|
||||
See sample: [`agent-permissions-intersect-with-assigner.good.al`](agent-permissions-intersect-with-assigner.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Permission sets or profiles that include User card, Permission Set Assignment, or agent-admin pages, or comments that the agent runs as SUPER regardless of who assigned it. Detection signal: default access controls or profile including user-administration objects.
|
||||
|
||||
See sample: `agent-permissions-intersect-with-assigner.bad.al`.
|
||||
See sample: [`agent-permissions-intersect-with-assigner.bad.al`](agent-permissions-intersect-with-assigner.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ The agent only sees what its profile shows. Extra actions, views, and Role Cente
|
|||
|
||||
Ship an agent-specific profile and page customizations: hide unrelated actions, keep descriptive tooltips, add Role Center links to the few pages the agent should open. Prefer fewer navigation hops.
|
||||
|
||||
See sample: `agent-profile-narrows-visible-ui.good.al`.
|
||||
See sample: [`agent-profile-narrows-visible-ui.good.al`](agent-profile-narrows-visible-ui.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Assigning `BUSINESS MANAGER` or `ORDER PROCESSOR` as `GetDefaultProfile` so the agent can do anything. Detection signal: default profile equal to a full-user role with no agent page customizations.
|
||||
|
||||
See sample: `agent-profile-narrows-visible-ui.bad.al`.
|
||||
See sample: [`agent-profile-narrows-visible-ui.bad.al`](agent-profile-narrows-visible-ui.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ Instance setup is not a Card or StandardDialog. The toolkit expects `PageType =
|
|||
|
||||
Declare `PageType = ConfigurationDialog`, host `part(...; "Agent Setup Part")`, and put agent-specific fields in another group. Keep system OK/Cancel. Use a temporary source record and defer persistence until Update, as described in `agent-setup-source-table-is-temporary.md`. Following Microsoft's agent setup samples, set `Extensible = false`.
|
||||
|
||||
See sample: `agent-setup-page-is-configuration-dialog.good.al`.
|
||||
See sample: [`agent-setup-page-is-configuration-dialog.good.al`](agent-setup-page-is-configuration-dialog.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
A Card or StandardDialog setup page with no `Agent Setup Part`. Detection signal: setup page ID from `IAgentFactory` / `IAgentMetadata` whose page is not `ConfigurationDialog` or has no `Agent Setup Part`.
|
||||
|
||||
See sample: `agent-setup-page-is-configuration-dialog.bad.al`.
|
||||
See sample: [`agent-setup-page-is-configuration-dialog.bad.al`](agent-setup-page-is-configuration-dialog.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ ConfigurationDialog setup is a draft: the user can Cancel without writing. That
|
|||
|
||||
Mark the page `SourceTableTemporary = true`. Copy into the temp record on open. Persist the Agent Setup buffer and custom fields only from the close path when the action is not Cancel, using `Agent Setup.GetChangesMade` / `SaveChanges`.
|
||||
|
||||
See sample: `agent-setup-source-table-is-temporary.good.al`.
|
||||
See sample: [`agent-setup-source-table-is-temporary.good.al`](agent-setup-source-table-is-temporary.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
A non-temporary source table, or `Insert`/`Modify` on the persisted setup row from field OnValidate. Detection signal: agent `ConfigurationDialog` without `SourceTableTemporary = true`, or database writes before Update.
|
||||
|
||||
See sample: `agent-setup-source-table-is-temporary.bad.al`.
|
||||
See sample: [`agent-setup-source-table-is-temporary.bad.al`](agent-setup-source-table-is-temporary.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ Each agent instance is a user. Instance-specific setup is keyed by that user's `
|
|||
|
||||
Give the setup table a Guid field `User Security ID` as the clustered primary key. Other settings are attributes of that key. When the page opens, `Get` or insert by the Guid the Agent Setup part already holds.
|
||||
|
||||
See sample: `agent-setup-table-keyed-by-user-security-id.good.al`.
|
||||
See sample: [`agent-setup-table-keyed-by-user-security-id.good.al`](agent-setup-table-keyed-by-user-security-id.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
A setup table keyed by Code, Integer, or with no Guid user key, then mapping one row to every instance. Detection signal: source table of the agent setup page whose primary key is not `User Security ID`.
|
||||
|
||||
See sample: `agent-setup-table-keyed-by-user-security-id.bad.al`.
|
||||
See sample: [`agent-setup-table-keyed-by-user-security-id.bad.al`](agent-setup-table-keyed-by-user-security-id.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ application-area: [all]
|
|||
|
||||
Validate inbound payloads in analysis: Error when the task must not run; Warning when a human must confirm. For outbound messages, adjust text in this method rather than in a later subscriber. Do not rely on skip-review to bypass warnings.
|
||||
|
||||
See sample: `analyze-message-error-stops-warning-forces-review.good.al`.
|
||||
See sample: [`analyze-message-error-stops-warning-forces-review.good.al`](analyze-message-error-stops-warning-forces-review.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Ignoring analysis entirely, or emitting Warning while documenting that `SetRequiresReview(false)` means unattended run. Detection signal: empty `AnalyzeAgentTaskMessage` plus skip-review on external input.
|
||||
|
||||
See sample: `analyze-message-error-stops-warning-forces-review.bad.al`.
|
||||
See sample: [`analyze-message-error-stops-warning-forces-review.bad.al`](analyze-message-error-stops-warning-forces-review.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ Page-filter tweaks, extra validation, and prompt dialogs for the agent should no
|
|||
|
||||
On `OnAfterInitialization`, exit unless `Agent Session.IsAgentSession`. Then `BindSubscription` a single-instance codeunit that holds the current task id. Keep those subscribers internal.
|
||||
|
||||
See sample: `bind-agent-subscribers-only-in-agent-session.good.al`.
|
||||
See sample: [`bind-agent-subscribers-only-in-agent-session.good.al`](bind-agent-subscribers-only-in-agent-session.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Event subscribers on `Sales Header` OnAfterInsert that always `Message` the agent, with no `IsAgentSession` guard. Detection signal: agent-only behaviour in a static subscriber that is not bind-gated.
|
||||
|
||||
See sample: `bind-agent-subscribers-only-in-agent-session.bad.al`.
|
||||
See sample: [`bind-agent-subscribers-only-in-agent-session.bad.al`](bind-agent-subscribers-only-in-agent-session.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ For isolation, `Agent`, `Agent Task Builder`, and related toolkit codeunits erro
|
|||
|
||||
Expose a public codeunit in the agent app (`Access = Public`) whose procedures take `User Security ID` and forward to `Agent` / `Agent Task Builder`. Document that surface as the integration contract. Keep toolkit calls inside that app.
|
||||
|
||||
See sample: `cross-app-agent-calls-need-your-public-api.good.al`.
|
||||
See sample: [`cross-app-agent-calls-need-your-public-api.good.al`](cross-app-agent-calls-need-your-public-api.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
From app B, calling `Agent.SetDisplayName` or `Agent.Create` with app A's metadata provider. Detection signal: toolkit agent APIs used with an `Agent Metadata Provider` value not declared in the same app.
|
||||
|
||||
See sample: `cross-app-agent-calls-need-your-public-api.bad.al`.
|
||||
See sample: [`cross-app-agent-calls-need-your-public-api.bad.al`](cross-app-agent-calls-need-your-public-api.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ application-area: [all]
|
|||
|
||||
Create instances from a setup page, a wizard, or another UI-driven path after the user is in a client session. Apply instructions and `Activate` there. For existing companies after an upgrade, document that an admin must open setup; do not create from the upgrade codeunit.
|
||||
|
||||
See sample: `do-not-create-agents-in-install-upgrade-or-background.good.al`.
|
||||
See sample: [`do-not-create-agents-in-install-upgrade-or-background.good.al`](do-not-create-agents-in-install-upgrade-or-background.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
`Agent.Create` inside `OnInstallAppPerCompany`, `OnUpgradePerCompany`, or a job-queue codeunit. The call fails at runtime even if it compiles. Detection signal: `Agent.Create` in `Subtype = Install`, `Subtype = Upgrade`, or a non-UI session.
|
||||
|
||||
See sample: `do-not-create-agents-in-install-upgrade-or-background.bad.al`.
|
||||
See sample: [`do-not-create-agents-in-install-upgrade-or-background.bad.al`](do-not-create-agents-in-install-upgrade-or-background.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ application-area: [all]
|
|||
|
||||
Insert only the permission sets the agent needs. For an AL `permissionset` object, use `Scope::System` and the ID of the app that defines it. Recreate permission sets that exist only as user-defined configuration in Business Central as AL objects first. Prefer a dedicated permission set over a full-user role.
|
||||
|
||||
See sample: `get-default-access-controls-least-privilege.good.al`.
|
||||
See sample: [`get-default-access-controls-least-privilege.good.al`](get-default-access-controls-least-privilege.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Empty `GetDefaultAccessControls`, or inserting `SUPER` / `D365 BUS FULL ACCESS` because it made the demo work. Detection signal: Role ID on the default buffer that is a full-user role, or a set that is not in the app.
|
||||
|
||||
See sample: `get-default-access-controls-least-privilege.bad.al`.
|
||||
See sample: [`get-default-access-controls-least-privilege.bad.al`](get-default-access-controls-least-privilege.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ application-area: [all]
|
|||
|
||||
Ship a `profile` object (and page customizations) in the app. In `GetDefaultProfile`, call `Agent.PopulateDefaultProfile` with that profile ID and `NavApp.GetCurrentModuleInfo`. Include UI-exported customizations as AL.
|
||||
|
||||
See sample: `get-default-profile-lives-in-the-app.good.al`.
|
||||
See sample: [`get-default-profile-lives-in-the-app.good.al`](get-default-profile-lives-in-the-app.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Setting `TempAllProfile."Profile ID"` to a client-only profile, or skipping `GetDefaultProfile`. Detection signal: factory default profile ID with no matching `profile` object in the app.
|
||||
|
||||
See sample: `get-default-profile-lives-in-the-app.bad.al`.
|
||||
See sample: [`get-default-profile-lives-in-the-app.bad.al`](get-default-profile-lives-in-the-app.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ The runtime treats instructions as the agent's standing prompt. A one-line goal
|
|||
|
||||
Store a document that states responsibilities, then non-negotiable guidelines (when to request a review, when not to post), then numbered steps for each task. Keep that text in the resource you pass to `SetInstructions`.
|
||||
|
||||
See sample: `instruction-structure-is-role-rules-steps.good.al`.
|
||||
See sample: [`instruction-structure-is-role-rules-steps.good.al`](instruction-structure-is-role-rules-steps.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
A single sentence such as Check customer credit for the sales order. Detection signal: instruction resource or `SetInstructions` payload with no responsibilities / guidelines / steps sections.
|
||||
|
||||
See sample: `instruction-structure-is-role-rules-steps.bad.al`.
|
||||
See sample: [`instruction-structure-is-role-rules-steps.bad.al`](instruction-structure-is-role-rules-steps.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ Agent tools are the UI the profile exposes. Action names and tool ids change acr
|
|||
|
||||
Write steps as business outcomes (release the order, set the hold reason). Tell the agent to memorize identifiers it must reuse. Do not hard-code action captions or tool ids.
|
||||
|
||||
See sample: `instructions-describe-work-not-tool-ids.good.al`.
|
||||
See sample: [`instructions-describe-work-not-tool-ids.good.al`](instructions-describe-work-not-tool-ids.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Instructions that say invoke SalesOrder.Post_Promoted or use tool page-42-action-3. Detection signal: instruction text containing Promoted action names or tool identifiers.
|
||||
|
||||
See sample: `instructions-describe-work-not-tool-ids.bad.al`.
|
||||
See sample: [`instructions-describe-work-not-tool-ids.bad.al`](instructions-describe-work-not-tool-ids.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ Static instructions stored as an app resource are copied onto an instance only w
|
|||
|
||||
In the upgrade codeunit, find existing instances of your metadata provider and call `SetInstructions` again with `NavApp.GetResourceAsText`. Guard with an upgrade tag so the rewrite runs once per version that changes the file.
|
||||
|
||||
See sample: `reapply-resource-instructions-on-upgrade.good.al`.
|
||||
See sample: [`reapply-resource-instructions-on-upgrade.good.al`](reapply-resource-instructions-on-upgrade.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Editing only the resource file, or calling `SetInstructions` solely from the first-time setup path. Detection signal: instruction resource in `resourceFolders` with no upgrade procedure that re-applies it.
|
||||
|
||||
See sample: `reapply-resource-instructions-on-upgrade.bad.al`.
|
||||
See sample: [`reapply-resource-instructions-on-upgrade.bad.al`](reapply-resource-instructions-on-upgrade.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ Each agent type needs a `Copilot Capability` enum value that the factory links a
|
|||
|
||||
Extend `Copilot Capability` with a unique value. In `OnInstallAppPerDatabase`, call `Copilot Capability.IsCapabilityRegistered` and, if false, `RegisterCapability` with availability, billing type, and a learn-more URL. Point `IAgentFactory` at that capability.
|
||||
|
||||
See sample: `register-copilot-capability-for-the-agent.good.al`.
|
||||
See sample: [`register-copilot-capability-for-the-agent.good.al`](register-copilot-capability-for-the-agent.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Shipping the agent enum without a `Copilot Capability` value, or adding the enum but never calling `RegisterCapability`. Duplicate ordinals across extensions also collide. Detection signal: agent metadata provider with no matching capability registration in an install codeunit.
|
||||
|
||||
See sample: `register-copilot-capability-for-the-agent.bad.al`.
|
||||
See sample: [`register-copilot-capability-for-the-agent.bad.al`](register-copilot-capability-for-the-agent.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ Instructions are instance data, not an enum caption. `Agent.SetInstructions` tak
|
|||
|
||||
Load instruction text from a resource or builder into a `SecretText` variable and call `Agent.SetInstructions(AgentUserSecurityId, Instructions)` after `Create`. Keep one instruction document per instance.
|
||||
|
||||
See sample: `set-instructions-as-secrettext.good.al`.
|
||||
See sample: [`set-instructions-as-secrettext.good.al`](set-instructions-as-secrettext.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Passing a `Label` or `Text` to `SetInstructions`, storing instructions in a setup Text field without wrapping as `SecretText`, or putting the prompt only in a code comment. Detection signal: `SetInstructions` with a non-`SecretText` argument, or no `SetInstructions` after `Create`.
|
||||
|
||||
See sample: `set-instructions-as-secrettext.bad.al`.
|
||||
See sample: [`set-instructions-as-secrettext.bad.al`](set-instructions-as-secrettext.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ application-area: [all]
|
|||
|
||||
Use `ShowCanCreateAgent` to decide discovery. If only agent administrators should see the type, return `Agent System Permissions.CurrentUserHasCanManageAllAgentsPermission`. Enforce extra policy inside your own create API. Never assume UI hiding blocks code.
|
||||
|
||||
See sample: `show-can-create-agent-does-not-block-code-create.good.al`.
|
||||
See sample: [`show-can-create-agent-does-not-block-code-create.good.al`](show-can-create-agent-does-not-block-code-create.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Returning `exit(false)` from `ShowCanCreateAgent` and then documenting that instances cannot be created, while page actions or other apps still call `Agent.Create`. Detection signal: `ShowCanCreateAgent` always false with no matching guard on programmatic create.
|
||||
|
||||
See sample: `show-can-create-agent-does-not-block-code-create.bad.al`.
|
||||
See sample: [`show-can-create-agent-does-not-block-code-create.bad.al`](show-can-create-agent-does-not-block-code-create.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ Incoming task messages default to requiring user approval before the agent runs.
|
|||
|
||||
Leave the default review-on for anything that originated outside your extension. Call `SetRequiresReview(false)` only on messages you constructed from already-authorized BC data.
|
||||
|
||||
See sample: `skip-incoming-review-only-for-trusted-input.good.al`.
|
||||
See sample: [`skip-incoming-review-only-for-trusted-input.good.al`](skip-incoming-review-only-for-trusted-input.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
`SetRequiresReview(false)` on simulated email, incoming webhooks, or user-free text. Detection signal: `SetRequiresReview(false)` next to external content with no prior validation.
|
||||
|
||||
See sample: `skip-incoming-review-only-for-trusted-input.bad.al`.
|
||||
See sample: [`skip-incoming-review-only-for-trusted-input.bad.al`](skip-incoming-review-only-for-trusted-input.bad.al).
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ The agent runtime looks for specific phrases: ask for assistance, request a revi
|
|||
|
||||
In the instruction resource, use those keywords at the decision points: request a review before posting; write an email only after stating that outbound mail is reviewed; memorize values the later steps need. Pair `Reply` / `Write an email` with an explicit review sentence.
|
||||
|
||||
See sample: `use-documented-instruction-keywords.good.al`.
|
||||
See sample: [`use-documented-instruction-keywords.good.al`](use-documented-instruction-keywords.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Inventing tool-like verbs (call Copilot, click Post_Promoted) or omitting request a review before posting. Detection signal: instruction text that says email the customer with no review keyword.
|
||||
|
||||
See sample: `use-documented-instruction-keywords.bad.al`.
|
||||
See sample: [`use-documented-instruction-keywords.bad.al`](use-documented-instruction-keywords.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
|
|
@ -17,13 +17,13 @@ An AL agent type is registered by extending `Agent Metadata Provider`. The platf
|
|||
|
||||
On the enum value, set `Implementation` for all three interfaces, each pointing at a dedicated codeunit. Keep factory (create, defaults, first-time setup), metadata (setup page, summary, annotations), and task execution (message analysis, intervention suggestions) in separate objects.
|
||||
|
||||
See sample: `wire-all-three-agent-interfaces.good.al`.
|
||||
See sample: [`wire-all-three-agent-interfaces.good.al`](wire-all-three-agent-interfaces.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
An `Agent Metadata Provider` value with no `Implementation`, only one interface mapped, or all three interfaces pointing at one catch-all codeunit that cannot satisfy the contracts. Detection signal: enumextension of `Agent Metadata Provider` whose value does not list `IAgentFactory`, `IAgentMetadata`, and `IAgentTaskExecution`.
|
||||
|
||||
See sample: `wire-all-three-agent-interfaces.bad.al`.
|
||||
See sample: [`wire-all-three-agent-interfaces.bad.al`](wire-all-three-agent-interfaces.bad.al).
|
||||
|
||||
## See also
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue