- Introduced guidelines for using the "CMFRT" prefix in object names, fields, and procedures to avoid naming collisions and ensure clarity. - Established rules for object ID ranges to prevent conflicts with other extensions and maintain historical integrity. - Documented best practices and anti-patterns for various coding patterns, including case statements, interface injection, label usage, and validation methods. - Implemented a standards review skill to evaluate AL source changes against CMFRT company standards, ensuring compliance with naming, permissions, and architectural patterns.
8.1 KiB
| kind | id | version | title | description | inputs | outputs | bc-version | technologies | countries | application-area | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| action-skill | cmfrt-standards-review | 1 | CMFRT AL standards review | Reviews AL source changes for CMFRT company standards — naming, object IDs, permission sets, breaking-changes, events, patterns, and architecture. |
|
|
|
|
|
|
CMFRT AL standards review
Reviews AL source changes against the CMFRT company standards defined in custom/knowledge/. This is a leaf action skill: it invokes no sub-skills. It is dispatched alongside microsoft/skills/review/al-code-review.md for every CMFRT project review.
An orchestrator invokes this skill with either a pr-diff (the standard PR-review entry point) or a file-path (single-file review). The skill produces a single JSON document conforming to the DO output contract.
Source
Read the BCQuality knowledge index once (knowledge-index.json at the checkout root). Take every entry whose layer is custom as the candidate set — this covers all domains under custom/knowledge/: naming, security, breaking-changes, events, patterns, and architecture. Do not open individual article files at this step.
Relevance
Apply frontmatter matching rules defined in READ against the task context:
bc-version— from the target branch'sapp.jsonor orchestrator context;unknownif absent.technologies—[al].countries— fromapp.jsonor orchestrator context; defaultunknown.application-area— union of application areas declared by changed objects;unknownif not determinable.
Discard candidates whose filter dimensions explicitly do not match. Retain conditionally applicable candidates (any dimension unknown); findings from those files MUST have confidence no higher than medium and the message MUST name the unknown dimension.
Worklist
Narrow the relevant candidates to those that apply to the changes under review. Compute overlap against:
- Changed AL object names, types, and IDs — weighted toward tables, table extensions, codeunits, interfaces, permission sets, and any object whose ID, name, or prefix is being set or changed. Match against the
namingandarchitecturedomain candidates. - Changed procedure signatures and parameter lists — especially global procedures being added, renamed, or extended. Match against
breaking-changesandeventscandidates. - Changed permission set objects and their
IncludedPermissionSetschains. Match againstsecuritycandidates. - Tokens extracted from the diff:
ObsoleteState,ObsoleteReason,ObsoleteTag,Confirm,case,else,interface,implements,IntegrationEvent,OnBefore,OnAfter,Handled,IsHandled,IncludedPermissionSets,Assignable,procedure,local procedure,Validate,Init,Insert,OnInsertRecord,Buffer,Caption,ToolTip,Label,Comment,CopyStr,MaxStrLen,TryFunction,Codeunit.Run,field(,value(. - Field-assignment shape: contiguous runs of
Record.Field := Valuestatements on a non-buffer record variable inside a creator/method codeunit. Match against thepatternscandidatecmfrt-validate-not-assign. - API page triggers:
PageType = APIcombined withSourceTableon a base application table, or anOnInsertRecordbody containingRec.Insertorexit(false). Match against thearchitecturecandidatecmfrt-buffer-table-api-pattern.
A candidate enters the worklist when its keywords intersect the extracted tokens, or when its topic (from the index path, title, and description) matches the type of change in the diff. Read an article's full body only after it enters the worklist.
Resolve layer-precedence conflicts per READ. Since all candidates are in the custom layer, no cross-layer conflict arises unless a microsoft or community file shares a concern; in that case the custom file takes precedence and the lower-precedence file is recorded in suppressed with reason: "layer-precedence".
When no custom knowledge survives filtering, emit outcome: "no-knowledge". When the worklist is empty because no candidates matched the diff, emit outcome: "completed" with an empty findings array.
Action
For each worklist entry, evaluate the diff against its ## Best Practice and ## Anti Pattern sections. Emit findings as follows:
- Clear Anti Pattern match: severity
majororblocker. Useblockeronly when the knowledge file explicitly states the pattern violates a platform-level guarantee. Otherwisemajor. - Code that contradicts a Best Practice without being a full anti-pattern: severity
minor. - File is clearly applicable but no violation is detectable: severity
infociting the file.
Set confidence to high for unambiguous token or structural matches, medium for heuristic matches or when any frontmatter dimension was unknown, and low for advisory-only applicability.
Emit findings[].suggested-code whenever the fix is small, local, and mechanical — for example: adding an else clause to a bare case, replacing a Confirm( call with ConfirmManagement.GetResponseOrDefault(, adding ObsoleteState = Pending to a deleted member, correcting a naming or caption prefix, rewriting Record.Field := Value as Record.Validate(Field, Value) (except primary-key/document-no. fields and buffer tables), or replacing a literal CopyStr length with MaxStrLen(Target.Field). The payload must be a literal replacement for the lines in location with no diff markers or commentary. If the fix is mechanical-looking but spans non-contiguous lines or requires context not visible in the diff, set suggested-code-omission-reason instead.
After evaluating all worklist entries, consider whether the diff exhibits a CMFRT standards violation the agent recognises from general AL knowledge that no custom knowledge file covers. Hold such candidates to the precision bar in skills/do.md (Agent findings): emit only concrete, material violations a CMFRT reviewer would agree are wrong. Encode as agent findings with references: [], id prefixed agent:, confidence capped at medium, severity capped at minor.
Outcome selection:
completed— every worklist item evaluated, including whenfindingsis empty.no-knowledge— no custom knowledge survived Source, Relevance, and configuration filtering.not-applicable— no AL changes in the diff ortechnologiesfilter rejected the task.partial— time or token budget exhausted before worklist completion; setoutcome-reason.failed— unrecoverable error; setoutcome-reason.
Output
Output conforms to the DO output contract. Example — naming and event violations found:
{
"skill": { "id": "cmfrt-standards-review", "version": 1 },
"outcome": "completed",
"summary": {
"counts": { "blocker": 0, "major": 1, "minor": 1, "info": 0 },
"coverage": { "worklist-size": 3, "items-evaluated": 3 }
},
"findings": [
{
"id": "custom/knowledge/naming/cmfrt-naming-prefix.md",
"severity": "major",
"message": "Procedure 'CalculateDiscount' on codeunit 2045710 has no CMFRT prefix. Rename to 'CMFRTBACalculateDiscount' to comply with the CMFRT naming convention.",
"location": { "file": "src/Sales/Discount.Codeunit.al", "line": 8 },
"references": [{ "path": "custom/knowledge/naming/cmfrt-naming-prefix.md" }],
"confidence": "high",
"suggested-code": " procedure CMFRTBACalculateDiscount(ItemNo: Code[20]; Qty: Decimal): Decimal"
},
{
"id": "custom/knowledge/events/cmfrt-onbefore-onafter-all-globals.md",
"severity": "minor",
"message": "Global procedure 'CMFRTBACalculateDiscount' has no OnBefore/OnAfter integration events. Add both events to allow dependent extensions to intercept or react to this operation.",
"location": { "file": "src/Sales/Discount.Codeunit.al", "line": 8 },
"references": [{ "path": "custom/knowledge/events/cmfrt-onbefore-onafter-all-globals.md" }],
"confidence": "high",
"suggested-code-omission-reason": "Event declarations span multiple non-contiguous locations in the file."
}
],
"suppressed": []
}