Appendix B: Metadata Type Risk Classification Matrix¶
This matrix classifies Salesforce metadata types into four risk tiers, Tier 0 to Tier 3, that govern automated PR workflow behaviour as described in Section 6. It is the canonical matrix: Section 6 defines the tiers and links here rather than repeating the assignments. The tiers classify metadata deployed to the org. Secrets and credentials are governed in Section 7, and configuration stored as records rather than metadata follows the Configuration Data standard. The classification is based on the potential blast radius of an erroneous change - the breadth of impact, reversibility, and likelihood of cascading failures across dependent components or data.
How this matrix is used in the pipeline: The tables on this page are the human-readable matrix; metadata-risk-tiers.yml is its machine-readable form, read by the pipeline. Tier 0 metadata is blocked outright rather than reviewed: its paths are listed in .forceignore and .gitignore, a GitHub push ruleset rejects any push containing them, a required PR status check fails any PR whose diff includes them, and a static analysis rule reports any file of a Tier 0 type at severity 1 (see Tier 0 Enforcement). A required workflow labels every PR with its highest risk tier, from Tier 0 to Tier 3. From qa upwards, Tier 1 changes require the architect team's approval through CODEOWNERS; on every branch, auto-merge is disabled for them (see Tier 1 Enforcement); a linked ITSM record is optional. Tier 2 applies the standard quality gate chain. Tier 3 is eligible for expedited review policies in mature teams.
This matrix should be maintained as a versioned artifact in the centralised configuration repository and reviewed periodically as the organisation's risk posture and the Salesforce platform evolve. It is intentionally a starting point - organisations should adjust tier assignments to reflect their specific regulatory environment, data sensitivity, and operational history.
Machine-Readable Matrix¶
The pipeline reads the matrix from metadata-risk-tiers.yml. Its canonical copy lives in the config/ directory of the configuration repository (Appendix D), and each project repository keeps its copy in .github/, where the two workflows that read it look by default (Repository Structure). The Prohibited Metadata Check reads its tier0 list, and the Metadata Risk Tier workflow reads the tier1, tier2, and tier3 lists. A metadata file that matches no list is treated as Tier 2, and the workflow warns about it, so that every new metadata type is classified here before it becomes routine in the codebase.
Expand to show the risk matrix file
# metadata-risk-tiers.yml
# Machine-readable metadata risk matrix.
# The paths below are examples only. Include every metadata type on your
# organisation's own list for each tier, not just these.
# Patterns use fnmatch syntax, the same as the Tier 0 push ruleset.
# A metadata file that matches no pattern is treated as Tier 2 (standard
# risk), and the risk tier workflow warns about it so it can be classified.
# Patterns are checked in order: tier0, tier1, tier2, tier3.
tier0:
- "**/flowDefinitions/**"
- "**/*.flowDefinition-meta.xml"
- "**/certs/**"
- "**/*.crt"
- "**/*.crt-meta.xml"
# External Client App global OAuth settings: consumer key and secret
- "**/extlClntAppGlobalOauthSets/**"
- "**/*.ecaGlblOauth-meta.xml"
# S-Controls: superseded by Visualforce pages
- "**/scontrols/**"
- "**/*.scf"
- "**/*.scf-meta.xml"
tier1:
- "**/sharingRules/**"
- "**/territory2Models/**"
- "**/namedCredentials/**"
- "**/externalClientApps/**"
- "**/extlClntAppOauthSettings/**"
- "**/extlClntAppOauthPolicies/**"
# Legacy: no new Connected Apps since Spring '26; existing ones remain
- "**/connectedApps/**"
- "**/authproviders/**"
- "**/customPermissions/**"
- "**/permissionsets/**"
- "**/permissionsetgroups/**"
- "**/profiles/**"
- "**/mutingpermissionsets/**"
# User access policies grant permission sets and groups automatically
- "**/useraccesspolicies/**"
# Experience Cloud: sharing sets give external users access to records,
# and audiences decide who sees a site's pages and content
- "**/sharingSets/**"
- "**/audience/**"
# Org settings: one settings file changes the behaviour of the whole org
- "**/settings/**"
- "**/objects/*__mdt/**"
- "**/platformEventChannels/**"
- "**/remoteSiteSettings/**"
- "**/cspTrustedSites/**"
- "**/corsWhitelistOrigins/**"
# Destructive manifests usually sit at the repository root, so match
# them both at the root and in subdirectories.
- "destructiveChanges*.xml"
- "**/destructiveChanges*.xml"
tier2:
- "**/classes/**"
- "**/triggers/**"
- "**/lwc/**"
- "**/aura/**"
- "**/pages/**"
# Custom objects and their fields, validation rules, record types,
# and custom setting definitions. Custom metadata types (__mdt) are
# Tier 1 and matched above.
- "**/objects/**"
- "**/flows/**"
- "**/workflows/**"
- "**/labels/**"
- "**/flexipages/**"
- "**/layouts/**"
- "**/queues/**"
- "**/assignmentRules/**"
- "**/duplicateRules/**"
- "**/matchingRules/**"
- "**/globalValueSets/**"
# Agentforce and AI metadata
- "**/aiAuthoringBundles/**"
- "**/bots/**"
- "**/botBlocks/**"
- "**/botTemplates/**"
- "**/genAiPlanners/**"
- "**/genAiPlannerBundles/**"
- "**/genAiPlugins/**"
- "**/genAiFunctions/**"
- "**/genAiPromptTemplates/**"
- "**/genAiPromptTemplateActivations/**"
- "**/aiApplications/**"
- "**/aiApplicationConfigs/**"
- "**/aiScoringModelDefinitions/**"
- "**/aiUsecaseDefinitions/**"
- "**/aiEvaluationDefinitions/**"
tier3:
- "**/staticresources/**"
- "**/translations/**"
- "**/prompts/**"
- "**/pathAssistants/**"
- "**/email/**"
- "**/reports/**"
- "**/dashboards/**"
- "**/documents/**"
Tier 0 - Prohibited Metadata¶
These metadata types are never stored in version control. They are managed directly in each org, and the pipeline blocks them at every layer described in Section 6.
| Metadata Type | API Name | Rationale |
|---|---|---|
| Flow Definition | FlowDefinition |
Salesforce manages the active Flow version server-side; committing FlowDefinition creates merge conflicts and provides no governance benefit. |
| Certificate | Certificate |
Should be managed manually in each org |
| External Client App Global OAuth Settings | ExtlClntAppGlobalOauthSettings |
Holds the app's OAuth consumer key and consumer secret, which must be protected; configured in each org, never committed. The rest of the app is Tier 1. |
| S-Control | Scontrol |
Superseded by Visualforce pages, and an org that has never used s-controls cannot create one; an existing s-control is rebuilt as a Visualforce page or a Lightning web component, never committed (Scontrol) |
Tier 0 Enforcement¶
The table above is the Tier 0 group, and each type in it is blocked at five layers. Its paths appear in three files and its type names in a fourth, the PMD ruleset, and all of them must agree. When a type is added to this table, update the files together:
.forceignoreand.gitignore: the entries below. The Salesforce CLI then never retrieves or deploys the paths, and Git does not stage them by accident.- Risk matrix file: the
tier0list inmetadata-risk-tiers.yml, which the required status check reads. - Push ruleset: the Tier 0 push ruleset in Appendix C rejects any push containing them.
- Required status check: the Prohibited Metadata Check in Appendix A fails any PR that adds or modifies them, and so fails the
Quality Gatescheck that every branch protection ruleset requires. It reads its paths from the risk matrix file rather than holding its own copy. - Static analysis rule: the PMD rule
ProhibitedMetadataTypeinpmd-custom-rules-metadata.xmlholds the same types in itsmetadataTypesproperty, each by its API name, which is the name of the root element of its file. The rule reports every metadata file of a listed type at severity 1. It reads what a file contains and not where it is, so it also reports a Tier 0 file saved under another name or in another folder. It reads XML only, so a certificate's.crtfile and an s-control's.scffile are left to the path checks.
The same block goes in both .forceignore and .gitignore, which share the same pattern syntax:
# Tier 0 - prohibited metadata. Never commit, retrieve, or deploy.
# The entries below are examples only. Include every item on your
# organisation's own Tier 0 list, not just these.
# Keep in step with the tier0 list in metadata-risk-tiers.yml, the Tier 0
# push ruleset, and the ProhibitedMetadataType rule.
# FlowDefinition: Salesforce manages the active Flow version server-side
**/flowDefinitions/
**/*.flowDefinition-meta.xml
# Certificate: managed manually in each org
**/certs/
**/*.crt
**/*.crt-meta.xml
# ExtlClntAppGlobalOauthSettings: holds the OAuth consumer key and secret
**/extlClntAppGlobalOauthSets/
**/*.ecaGlblOauth-meta.xml
# Scontrol: superseded by Visualforce pages
**/scontrols/
**/*.scf
**/*.scf-meta.xml
Tier 1 - High Risk Metadata¶
| Metadata Type | API Name | Rationale |
|---|---|---|
| Sharing Rules | SharingRules |
Controls record visibility; misconfiguration can expose sensitive data org-wide |
| Territory Management | Territory2, Territory2Model |
Affects record access for large user populations |
| Named Credentials | NamedCredential |
Governs authentication to external systems |
| External Client Apps | ExternalClientApplication, ExtlClntAppOauthSettings, ExtlClntAppOauthConfigurablePolicies |
Controls OAuth flows and external system access. The app's global OAuth settings file is Tier 0 |
| Connected Apps (legacy) | ConnectedApp |
Existing Connected Apps keep working and stay Tier 1; new ones can no longer be created (Spring '26), so new integrations use External Client Apps |
| Auth Providers | AuthProvider |
Governs SSO and identity federation |
| Custom Permissions | CustomPermission |
Used in permission set and flow-based access control |
| Permission Sets | PermissionSet |
Grants object, field, and system permissions |
| Permission Set Groups | PermissionSetGroup |
Aggregates permission sets |
| Profiles | Profile |
Broad access control surface |
| Muting Permission Sets | MutingPermissionSet |
Removes permissions from permission set groups |
| User Access Policies | UserAccessPolicy |
Grants or revokes permission sets, permission set groups, licences, public groups, and queues for every user it matches, by itself when users are created or updated |
| Sharing Sets | SharingSet |
Gives Experience Cloud users access to records that are related to their account or contact |
| Audiences | Audience |
Decides which Experience Cloud users see a site's pages and content |
| Org Settings | Settings (every type, such as SecuritySettings, SharingSettings, and FlowSettings) |
One file changes the behaviour of the whole org: its security, its sharing model and OWD, how Flows deploy, and more |
| Custom Metadata Types | CustomObject (__mdt) |
Often used for configuration-as-data patterns |
| Platform Events | PlatformEventChannel |
Changes can break event-driven integrations |
| Remote Site Settings | RemoteSiteSetting |
Controls which endpoints Apex callouts can reach; some orgs promote these to Tier 0 and manage them in each org |
| CSP Trusted Sites | CspTrustedSite |
Controls which domains LWC components can load from |
| CORS Allowlist Origins | CorsWhitelistOrigin |
CORS allowlist entries apply to REST API and Lightning Out requests. |
| Destructive Changes | destructiveChanges.xml |
Any destructive change manifest |
Profiles and permission sets get more scrutiny than their tier alone gives them: the permissions that block a change outright, and further metadata governance rules, are set out on the Permissions and Security page.
Tier 1 Enforcement¶
Tier 1 changes are governed at three points:
- Risk matrix file: the
tier1list inmetadata-risk-tiers.yml. - Required status check: the Metadata Risk Tier workflow labels the PR
risk: tier-1and disables auto-merge, so a Tier 1 change is always merged by hand. It also comments on each Tier 1 file in the diff, with the reason for the review, and asks the reviewer to resolve the conversation when the review of that file is done. The branch rulesets do not let the pull request merge while a conversation is open. CODEOWNERS: the block below makes the architect team the code owner of every Tier 1 path. The rulesets ofqa,staging, andmainrequire code owner review (Appendix C), so fromqaupwards no Tier 1 change merges without the architect team's approval. Onint, one peer approves a Tier 1 change, as for any other change (Approvals).
# Tier 1 - high risk metadata. The architect team reviews every change.
# The entries below are examples only. Include every item on your
# organisation's own Tier 1 list, not just these.
# Keep in step with the tier1 list in metadata-risk-tiers.yml.
# Place this block at the end of CODEOWNERS, after the governance block:
# the last matching pattern takes precedence.
**/sharingRules/ @<my-org>/architect-team
**/territory2Models/ @<my-org>/architect-team
**/namedCredentials/ @<my-org>/architect-team
**/externalClientApps/ @<my-org>/architect-team
**/extlClntAppOauthSettings/ @<my-org>/architect-team
**/extlClntAppOauthPolicies/ @<my-org>/architect-team
**/connectedApps/ @<my-org>/architect-team
**/authproviders/ @<my-org>/architect-team
**/customPermissions/ @<my-org>/architect-team
**/permissionsets/ @<my-org>/architect-team
**/permissionsetgroups/ @<my-org>/architect-team
**/profiles/ @<my-org>/architect-team
**/mutingpermissionsets/ @<my-org>/architect-team
**/useraccesspolicies/ @<my-org>/architect-team
**/sharingSets/ @<my-org>/architect-team
**/audience/ @<my-org>/architect-team
**/settings/ @<my-org>/architect-team
**/objects/*__mdt/ @<my-org>/architect-team
**/platformEventChannels/ @<my-org>/architect-team
**/remoteSiteSettings/ @<my-org>/architect-team
**/cspTrustedSites/ @<my-org>/architect-team
**/corsWhitelistOrigins/ @<my-org>/architect-team
**/destructiveChanges*.xml @<my-org>/architect-team
Tier 2 - Standard Risk Metadata¶
| Metadata Type | API Name | Notes |
|---|---|---|
| Apex Classes | ApexClass |
Standard gate chain; test coverage enforced |
| Lightning Web Components | LightningComponentBundle |
Jest tests required; Code Analyzer gates apply |
| Aura Components | AuraDefinitionBundle |
Code Analyzer ESLint gate applies |
| Visualforce Pages | ApexPage |
Standard gate chain |
| Custom Objects | CustomObject |
Review for downstream impact |
| Custom Fields | CustomField |
Field type changes and deletions are higher risk |
| Validation Rules | ValidationRule |
Can block record saves |
| Apex Triggers | ApexTrigger |
Execute on DML operations; poorly tested triggers can cause data corruption |
| Flows (Active) | Flow |
Active Flows execute in user and system contexts |
| Process Builder | Flow (Process type) |
Legacy automation; same risk profile as Flows |
| Workflow Rules | WorkflowRule |
Legacy automation that executes on record save |
| Agentforce Agent Bundle | AiAuthoringBundle |
Top-level SFDX bundle packaging agent definitions, planners, and versioning artifacts (API v65.0+) |
| Agentforce Agent / Bot | Bot, BotVersion |
Core agent definition; governs agent behaviour, topics, and data access scope |
| Agent Dialog Block | BotBlock |
Reusable conversational dialogue blocks referenced by agents |
| Agent Template | BotTemplate |
Reusable agent templates for rapid agent creation |
| AI Planner | GenAiPlanner |
Controls agent reasoning strategy and action selection |
| AI Planner Bundle | GenAiPlannerBundle |
Packages planner configuration for deployment with an agent |
| AI Plugin / Action | GenAiPlugin |
Defines actions an agent can invoke; overpermissioned agents can exfiltrate data |
| AI Function | GenAiFunction |
Custom callable functions exposed to AI agents |
| AI Prompt Template | GenAiPromptTemplate, GenAiPromptTemplateActv |
Agent instructions and prompt configurations; manipulated templates can alter agent behaviour |
| AI Application | AIApplication, AIApplicationConfig |
Einstein AI application definition and configuration (API v50.0+) |
| AI Scoring Model | AIScoringModelDefinition |
Einstein Prediction Builder scoring model definition (API v58.0+) |
| AI Usecase Definition | AIUsecaseDefinition |
Einstein AI use case configuration (API v56.0+) |
| AI Evaluation Definition | AiEvaluationDefinition |
Agentforce testing and evaluation framework definitions (API v65.0+) |
| Custom Labels | CustomLabel |
Deletion can break dependent code and LWC |
| Custom Settings | CustomObject (definition) |
The setting values are configuration data, not metadata |
| Lightning Pages | FlexiPage |
UI layout changes |
| Page Layouts | Layout |
Affects field visibility |
| Record Types | RecordType |
Affects picklist values and page layout assignments |
| Queues | Queue |
Affects record assignment |
| Assignment Rules | AssignmentRule |
Governs automated record assignment |
| Duplicate Rules | DuplicateRule |
Controls duplicate detection |
| Matching Rules | MatchingRule |
Underlies duplicate detection |
| Global Value Sets | GlobalValueSet |
Deletions affect all dependent fields |
Tier 3 - Low Risk Metadata¶
| Metadata Type | API Name | Notes |
|---|---|---|
| Static Resources | StaticResource |
File assets; changes are isolated |
| Translations | Translations |
Localisation strings; no functional impact |
| In-App Guidance | Prompt |
User guidance overlays |
| Path Assistant | PathAssistant |
Sales path UI configuration |
| Email Templates | EmailTemplate |
Content templates; minimal code risk |
| Reports | Report |
Reporting configuration |
| Dashboards | Dashboard |
Reporting visualisation |
| Documents | Document |
Legacy documents |
Static resources and JavaScript: Static resources are Tier 3, but the tier system governs only how a change is approved: a static resource does not need elevated review. It does not, however, mean that the contents go unchecked. Every JavaScript library in a static resource is scanned for known vulnerabilities in several ways, when a PR is submitted and at other times, including with RetireJS (see Dependency Scanning and Appendix E).
Depending on permissions given to users, Reports, Dashboards, Email Templates, and Documents may be pulled from Production to the pipeline branches regularly, which does raise the risk of merge conflicts.
Notes on Matrix Maintenance¶
Tier promotion: Individual metadata types may warrant promotion to a higher tier based on organisational context. A Custom Label read by Apex code controlling feature flags behaves more like Tier 1 than Tier 2.
New metadata types: Salesforce introduces new metadata types with each major release. New types should be assessed against the Tier 1 criteria and added to this matrix before they appear in the codebase.
Destructive changes override: Any PR containing destructiveChanges.xml or destructiveChangesPre.xml is treated as Tier 1 regardless of which metadata types are listed in the manifest.