Chalky · Rule registry

Every rule we check. Every source. Every one we turned down.

51 rules across two scans, each naming the Salesforce documentation or practitioner guidance behind it, plus 7 we are still testing and do not charge for. The checks we looked at and declined are here too, with the reasoning — that is the part most registries leave out.

What we declined

Checks we looked at and did not adopt

A rule we reject leaves a record with a reason. A rule we ignore gets rediscovered next year by someone repeating the same work. These are dated so you can see what we knew and when.

SF-flow-test-coverage

declined30 August 2026

Evaluated and deferred, sweep 2. Winter '27 adds Flow Test Mode with code coverage, which would make "flows should have tests" detectable for the first time. Declined for now on one ground only: Test Mode is Beta and Winter '27 is not yet GA, so a rule requiring tests would demand something the platform does not yet reliably offer. Captured rather than ignored, and this should be revisited the moment Test Mode reaches GA — it is the strongest new rule candidate found in this sweep.

https://www.salesforceben.com/17-new-salesforce-flow-features-in-winter-27/

LFS-missing-start-reference

declined30 August 2026

Evaluated and declined, sweep 1. LFS ships missing-start-reference, which fires when a flow has no start node. Captured rather than ignored, and demoted: a flow with no start node cannot be activated in Salesforce, so it cannot be a live defect in a scanned production org. It guards malformed metadata during authoring, which is a linting concern rather than an audit finding. Reversible if a real org ever presents one.

https://github.com/Flow-Scanner/lightning-flow-scanner/blob/main/packages/core/src/main/rules/MissingStartReference.ts

What changed

Last change: 30 August 2026

We scan the sources weekly and publish when something moves. A quiet month here means a quiet month in the evidence, not that we stopped looking.

30 August 2026FL-037changedNo copy of element API names
30 August 2026FL-032changedNo unused variables
30 August 2026FL-019changedFlow must not run in system mode without sharing
30 August 2026SF-flow-test-coveragedeclinedSF-flow-test-coverage
30 August 2026FL-025changedFlow size and complexity ceiling
30 August 2026FL-037newNo copy of element API names
30 August 2026LFS-missing-start-referencedeclinedLFS-missing-start-reference
30 August 2026FL-011changedGet records naming convention
30 August 2026FL-010changedVariable naming convention
30 August 2026FL-002changedFlow naming convention
30 August 2026FL-017newComplex elements must have descriptions
30 August 2026FL-008newUse before save for same record updates
30 August 2026FL-024newNo active process builder or workflow processes
30 August 2026FL-012newEntry criteria on record triggered flows
30 August 2026FL-032newNo unused variables
30 August 2026FL-020newNo synchronous callouts in record triggered flows
30 August 2026FL-021newNo actions or subflows inside loops
30 August 2026FL-022newUpdate triggers must gate on changed values
30 August 2026FL-023newRecord triggered flows must set trigger order
30 August 2026FL-030newDecision default outcome must be deliberate
30 August 2026FL-018newFlow error messages must be user friendly
30 August 2026FL-011newGet records naming convention
30 August 2026FL-002newFlow naming convention
30 August 2026FL-010newVariable naming convention
30 August 2026FL-033newInactive flows should be removed
30 August 2026FL-015newNo wait elements in record triggered flows
30 August 2026FL-016newUpdate records should use record variables
30 August 2026FL-026newNo hardcoded credentials or secrets
30 August 2026FL-027newNo hardcoded URLs
30 August 2026FL-028newNo DML between screens with back navigation
30 August 2026FL-029newNo unreachable elements
30 August 2026FL-036newPrefer records over ID strings
30 August 2026FL-035newPrefer transform over assignment loops
30 August 2026RC-006newContext definition with both ClonedFrom and InheritedFrom
30 August 2026RC-010newNo default pricing procedure fallback
30 August 2026RC-007newCloned context definition missing standard mappings
30 August 2026RC-008newStale decision table
30 August 2026FL-009newAutomation bypass mechanism
30 August 2026RC-012newSKU proliferation standing in for attributes
30 August 2026RC-013newCatalog hygiene floor

Showing the 40 most recent of 67 recorded changes.

Salesforce Flow

36 rules, and 1 in beta

Salesforce Flow Best Practice Rules v1.6.0. Open a rule for what it requires, why it matters, how to fix it, and where it comes from. A rule marked beta runs and is reported but is not charged for. Tell us whether a rule is worth checking — votes and comments both go to a person, and we publish what we change.

FL-001Flow must have descriptionMediumMaintainability

What it requires. Every Flow must have a populated description field explaining its purpose, the objects it touches, where it is invoked from, and the business process it supports.

Why it matters. Without a description, the next person to maintain the flow has no context for what it does, why it exists, or what it touches. This significantly increases debugging and handover time.

How to fix it. Populate the description field with: what the flow does, which objects it touches, where it is invoked from, and its entry criteria.

Source. Salesforce Admins: The Ultimate Guide to Flow Best Practices and Standards (official Salesforce publication, updated 17 July 2025) – Document your flows: fill in the description field

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-002Flow naming conventionMediumMaintainability

What it requires. Flow API names must follow the convention: [Domain]_[TypeCode]_[Action]. Domain is typically the primary object. TypeCode must be one of: SCR, SFL, SCH, BeforeSave, AfterSave, BeforeCreate, AfterCreate, BeforeUpdate, AfterUpdate, BeforeDelete, AfterDelete, EVT, EML.

Why it matters. A consistent naming convention allows any team member to understand a flow's type, trigger context, and purpose from its name alone, without opening it.

How to fix it. Rename the flow to follow [Domain]_[TypeCode]_[Action] convention. Refer to the SFXD Flow Naming Conventions guide for the full type code list.

Source. SFXD Wiki: Flow Naming Conventions – Meta-Flow Naming. Community standard; the Salesforce Admins flow best practices guide links this wiki for naming conventions

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-003No hardcoded IDsHighReliability

What it requires. Flows must not contain hardcoded Salesforce record IDs for Record Types, Queues, Owners, Groups, or any other org-specific records.

Why it matters. Record IDs differ between environments (Dev, QA, UAT, Production). Hardcoded IDs cause flows to fail silently or throw errors when deployed across environments. They are invisible to reviewers scanning for environment-specific dependencies.

How to fix it. Replace hardcoded IDs with a Get Records lookup using the DeveloperName field on the relevant setup object (RecordType, Group, etc.), or store the developer name in Custom Metadata and retrieve it at runtime.

Source. Salesforce Admins: The Ultimate Guide to Flow Best Practices and Standards – Hard coding IDs: use Get Records on DeveloperName or Custom Metadata instead

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-004No DML inside loopsHighPerformance

What it requires. Get Records, Create Records, Update Records, and Delete Records elements must not appear inside a Loop element in record-triggered or autolaunched flows.

Why it matters. Each SOQL query inside a loop counts against the per-transaction limit of 100 synchronous SOQL queries. Each DML statement inside a loop counts against the limit of 150 DML statements per transaction. Each DML-affected record counts against the 10,000 DML rows limit. A loop processing 101 records with a Get Records element will throw a System.LimitException and halt the entire transaction mid-execution, leaving records in a partially updated state.

How to fix it. Move all Get Records and DML elements outside the loop. Use Assignment elements inside the loop to build collections, then perform a single bulk DML operation after the loop completes.

Source. Apex Developer Guide: Execution Governors and Limits (100 SOQL queries / 150 DML statements per synchronous transaction). Practice guidance: Salesforce Admins Ultimate Guide – Being careless when looping

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-005Fault paths requiredHighReliability

What it requires. All DML elements (Create Records, Update Records, Delete Records) and Apex Action elements must have a fault path connector configured.

Why it matters. Without fault paths, any runtime error – including governor limit exceptions, permission errors, or database failures – produces a generic unhandled exception visible to the end user and sends no notification to administrators. Fault paths allow controlled error handling, user-friendly messages, and error logging.

How to fix it. Add a fault path to every DML and Apex Action element. At minimum, route to a screen element with a user-friendly message for screen flows, or an email alert for autolaunched flows. Consider a shared error-handling subflow for consistency.

Source. Salesforce Help: Customize What Happens When a Flow Fails (fault paths)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-006Null checks after get recordsHighReliability

What it requires. Every Get Records element must be immediately followed by a Decision element that checks whether the query returned a result (IsNull or IsEmpty check on the output variable). The null or empty outcome must route to an explicit error or exit path.

Why it matters. If a Get Records element returns no results and the flow proceeds without checking, any subsequent element that references the output variable will operate on a null value. This produces silent data errors, incorrect assignments, or runtime exceptions depending on context. This is one of the most common causes of UAT-passing flows failing in production.

How to fix it. After every Get Records element, add a Decision element with an IsNull or IsEmpty check on the output variable. Route the null/empty outcome to an appropriate error or exit path.

Source. Salesforce Admins: The Ultimate Guide to Flow Best Practices and Standards – Not checking for gaps in your logic (null and empty query results)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-007No hardcoded business logic valuesMediumMaintainability

What it requires. Business logic values that are subject to change – such as discount thresholds, SLA days, numeric limits, queue developer names, and owner IDs – must not be hardcoded as literals in Decision or Assignment elements. They should be stored in Custom Labels or Custom Metadata.

Why it matters. Hardcoded values require a developer to edit, test, and deploy the flow every time a business rule changes. Custom Metadata and Custom Labels allow business users or admins to update values without a deployment. Note: stable, infrequently changed values such as fixed product names or business unit identifiers carry lower practical risk than high-churn values such as discount thresholds or SLA targets.

How to fix it. Move business-owned values into Custom Labels (simple text and numbers) or Custom Metadata (structured, multi-field configurations). Reference these in the flow rather than literal values.

Source. Salesforce Admins: The Ultimate Guide to Flow Best Practices and Standards – Do not overload flows with hard-coded logic: use Custom Metadata, Custom Settings, or Custom Labels

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-008Use before save for same record updatesMediumPerformance

What it requires. Record-triggered flows that only update fields on the record that triggered the flow must use Before Save context, not After Save.

Why it matters. Before Save flows update the triggering record without consuming a DML statement. Each DML statement counts against the per-transaction limit of 150. In orgs with multiple flows and triggers on the same object, unnecessary After Save DML statements accumulate quickly and can push a transaction over the limit. Before Save flows also execute faster as they avoid a separate database write.

How to fix it. Convert the flow to Before Save context. Before Save flows can directly set fields on the triggering record via Assignment elements without a separate Update Records element.

Source. Salesforce Architects: Record-Triggered Automation decision guide – same-record field updates belong in before-save flows

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-009Automation bypass mechanismMediumMaintainability

What it requires. Record-triggered and autolaunched flows must include a bypass mechanism (Custom Metadata flag, Custom Setting flag, or custom permission check) that allows automation to be disabled without deployment, for use during data loads and sandbox seeding.

Why it matters. Without a bypass, bulk data loads – sandbox seeding, migrations, data fixes – trigger all automation on every affected record. A bulk load of 200 Contacts will invoke a Contact record-triggered flow 200 times within the same or consecutive transactions, rapidly consuming SOQL and DML governor limits and potentially causing the entire load job to fail. A bypass allows administrators to disable flows safely without a deployment.

How to fix it. Add a Custom Metadata type (e.g. Flow_Bypass__mdt) with a boolean Active field keyed by flow developer name; at the start of each applicable flow, fetch this record and exit immediately if the bypass is active. A custom permission check (for example an entry condition or Decision on $Permission.Bypass_Flow) is an equally acceptable mechanism, and suits per-user bypass where an integration or data-load user should skip automation that still runs for everyone else.

Source. Salesforce Admins: The Ultimate Guide to Flow Best Practices and Standards – Build a bypass in your flows

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-010Variable naming conventionLowMaintainability

What it requires. Flow variables must follow the SFXD naming convention: var_ prefix for all variables, var_coll_ for collections, var_sObj_ for record variables. Formulas must start with form_. Decisions must start with DEC_ or CHECK_. Assignments must start with SET_, ASSIGN_, STORE_, REMOVE_, or CALC_. Loops must start with LOOP_.

Why it matters. Consistent element naming allows any team member to understand the type and purpose of a variable or element at a glance, without reading its configuration. Auto-generated names (Variable1, Decision2) are unacceptable in a production flow.

How to fix it. Rename all variables and elements to follow the SFXD convention. Establish this as a team standard and enforce it in code review.

Source. SFXD Wiki: Flow Naming Conventions – Flow Elements. Community standard; the Salesforce Admins flow best practices guide links this wiki for naming conventions

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-011Get records naming conventionLowMaintainability

What it requires. Get Records elements must be named with a Get_ prefix. Custom Metadata or Custom Settings fetch elements must use a Fetch_ prefix. Create, Update, and Delete elements must use Create_, Update_, and Del_ prefixes respectively.

Why it matters. DML element prefixes immediately communicate the type of database operation being performed, making flows easier to audit for governor limit risks and easier to understand during reviews.

How to fix it. Rename all DML elements to include the correct prefix per the SFXD naming convention.

Source. SFXD Wiki: Flow Naming Conventions – DMLs. Community standard; the Salesforce Admins flow best practices guide links this wiki for naming conventions

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-012Entry criteria on record triggered flowsHighPerformance

What it requires. Record-triggered flows must define entry criteria (trigger filters) that restrict execution to only the records and field changes that require processing. A flow with no entry criteria runs on every save of every record of that object type, regardless of relevance.

Why it matters. A record-triggered flow with no entry criteria executes on every insert, update, or delete of the triggering object. In an org with thousands of records, this means the flow runs on every record save across all users and all integrations, consuming CPU time and potentially SOQL queries on every transaction regardless of whether the flow's logic applies. This accumulates rapidly in high-volume orgs and compounds with other flows and triggers sharing the same 10,000ms CPU time limit per transaction.

How to fix it. Add entry criteria to the flow trigger that restrict execution to the specific field changes or record conditions that require the flow's logic. Use IsChanged() for field-change-driven flows. For flows that must run on all saves, document the reason in the flow description.

Source. Salesforce Architects: Record-Triggered Automation decision guide – entry conditions. Also Salesforce Admins Ultimate Guide – Use entry criteria

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-013Get records must have filtersHighPerformance

What it requires. Every Get Records element must have at least one filter condition defined. Unfiltered Get Records queries retrieve all records of the target object up to the 50,000 record SOQL retrieval limit, which causes flows to fail in any org with meaningful data volumes.

Why it matters. Salesforce enforces a hard limit of 50,000 records retrieved by SOQL queries per transaction. An unfiltered Get Records element on a high-volume object such as Contact, Account, or Opportunity will hit this limit as the org grows, throwing a System.LimitException and halting the transaction. This is a latent failure: the flow works in a fresh sandbox and breaks silently in production as record counts increase.

How to fix it. Add specific filter conditions to every Get Records element to restrict the query to only the records the flow requires. Never query an entire object without a limiting filter. If a broad query is genuinely required, document the reason and ensure the result set will remain well below 50,000 records.

Source. Apex Developer Guide: Execution Governors and Limits – 50,000 rows retrieved by SOQL queries per transaction

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-014Flow API version must be currentMediumPerformance

What it requires. Flows must run on API version 57.0 or higher. Flows below this version are still subject to the 2,000 flow element execution limit that was removed in Spring 23, and miss subsequent platform bug fixes and security improvements.

Why it matters. The 2,000 element execution limit was removed in API version 57.0 (Spring 23). Flows on older versions hitting this limit will throw a System.LimitException mid-execution, leaving records in a partially updated state. Older API versions also miss significant platform improvements released since Spring 23.

How to fix it. Open the flow in Flow Builder, go to the flow properties, and update the API version to the current release version. Re-test the flow after upgrading as behaviour changes between API versions may apply.

Source. Salesforce Knowledge: Flow error 'Number of Iterations Exceeded' – the 2,000 executed element limit applies below API version 57.0; removed at 57.0 (Spring '23)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-015No wait elements in record triggered flowsMediumReliability

What it requires. Record-triggered flows must not contain Wait elements or Scheduled Paths. Wait elements in record-triggered flows create Paused Flow Interviews that sit in the system consuming org resources and potentially holding record locks indefinitely.

Why it matters. A Paused Flow Interview holds a snapshot of the record at the time of pausing, which can conflict with subsequent record updates. Paused interviews also count against org limits, can prevent record deletion, and create operational overhead for administrators who must manage and resume or delete them manually. Scheduled logic in record-triggered flows should be implemented via Scheduled Flows instead.

How to fix it. Remove Wait elements and Scheduled Paths from record-triggered flows. Move time-based logic into a dedicated Scheduled Flow that queries for records meeting the criteria and processes them in bulk.

Source. SFXD Wiki: Flow Structural Conventions – long Wait elements. Community standard. Paused interview limits: Salesforce Help, General Flow Limits

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-016Update records should use record variablesLowMaintainability

What it requires. Update Records elements should reference a record variable rather than setting fields individually using the Set Fields Manually option. Field-by-field assignment in the Update Records element requires manual maintenance whenever the set of fields to update changes.

Why it matters. When fields are set manually in an Update Records element, each field must be individually added, removed, or modified in the flow builder as requirements change. Using a record variable that is populated by Assignment elements before the Update Records call centralises the field population logic, makes the flow easier to read, and reduces the risk of fields being accidentally omitted during maintenance.

How to fix it. Refactor Update Records elements to use a record variable. Create a record variable of the appropriate object type, use Assignment elements to set the required field values, then reference the variable in the Update Records element.

Source. SFXD Wiki: Flow Structural Conventions – do not use Set Fields Manually on Update elements. Community standard

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-017Complex elements must have descriptionsLowMaintainability

What it requires. Apex action calls, subflow invocations, and Decision elements must have a description field populated explaining their purpose. This is distinct from the flow-level description (FL-001) and applies to individual element annotations within the flow.

Why it matters. Complex elements – particularly Apex actions, which invoke external code, and subflows, which invoke separate automation – are opaque without descriptions. A reviewer looking at the flow canvas cannot determine what an Apex action does or why a Decision branches the way it does without opening and reading each element. Descriptions make flows readable without requiring element-by-element inspection.

How to fix it. Add descriptions to all Apex action, subflow, and Decision elements. The description should state: what the element does, what inputs it uses, and what it outputs or decides.

Source. Salesforce Admins: The Ultimate Guide to Flow Best Practices and Standards – Document every step

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-018Flow error messages must be user friendlyAdvisoryMaintainability

What it requires. Custom error messages displayed to users from flow Custom Errors elements must be written in plain English, explain what went wrong in business terms, and avoid exposing technical detail such as field API names, element names, or system error codes.

Why it matters. Users encountering a flow error mid-process need to understand what happened and what to do next. An error message containing technical content such as field API names or internal codes causes confusion, erodes trust, and generates avoidable support calls. A well-formed error message states the business condition that was not met and directs the user to an appropriate next action.

How to fix it. Rewrite all custom error messages in plain English. State the business condition that prevented the action, avoid all technical terminology, and direct the user to a specific next step or team contact.

Source. Salesforce Ben – Quick Guide to Fault Paths in Salesforce Flow: the default "An unhandled fault has occurred" message is vague and frustrates users; display a clearer, user-friendly message that explains what went wrong.

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-019Flow must not run in system mode without sharingHighSecurity

What it requires. Flows must not run in System Context Without Sharing unless the elevation is deliberate, documented, and justified. The run mode must be the default running-user context or, where system access is genuinely required, System Context With Sharing with minimum permissions.

Why it matters. A flow in System Context Without Sharing reads and writes all records, ignoring sharing rules entirely. For screen flows and any flow reachable by portal or guest users, this exposes data the running user could never otherwise see. The Well-Architected framework's stated pattern is the most restrictive execution context possible; its named anti-pattern is running in system mode regardless of what the flow performs.

How to fix it. Set the flow's run mode to the default running-user context. Where elevated access is genuinely required, prefer System Context With Sharing, grant the minimum object and field permissions the flow needs, and record the justification in the flow description. From Winter '27 there is a direct fix: select "User Context—Enforces User Permissions" in the How to Run the Flow menu of an autolaunched or screen flow. The flow then runs in the running user's context regardless of how it is invoked, so it can only read and change what that user could. Prefer this to justifying an elevation.

Source. Salesforce Well-Architected, Trusted - Secure: Security Considerations for Flow Design. Also Salesforce Help: Flow Run Context Winter '27 adds the User Context—Enforces User Permissions run option.

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-020No synchronous callouts in record triggered flowsHighReliability

What it requires. Record-triggered flows must not invoke external-system actions (External Services, HTTP callout actions, or other outbound integrations) on the immediate, synchronous path. External calls belong on an asynchronous path that runs after the record change commits.

Why it matters. A callout attempted while the record save transaction is open fails at runtime; asynchronous paths exist in record-triggered flows precisely to reach external systems after commit. The Well-Architected pattern is that flows involving external system callouts or long-running processes use asynchronous paths.

How to fix it. Move external-system actions onto a Run Asynchronously path or a scheduled path, with fault paths handling their failures on that path.

Source. Salesforce Well-Architected, Easy - Automated: data handling patterns. Also the Salesforce release note: Connect a Record-Triggered Flow to an External System Using an Asynchronous Path

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-021No actions or subflows inside loopsMediumPerformance

What it requires. Apex actions, invocable actions, email actions, and subflow calls must not appear inside a Loop element. This extends the ban on queries and DML in loops to every element that consumes per-invocation limits.

Why it matters. Flow bulkification batches executions of the same element across interviews, but an action inside a loop still executes once per iteration within each interview, multiplying Apex, email, and callout limit consumption exactly as DML in a loop does. A loop of 200 iterations calling an Apex action makes 200 invocations in one transaction.

How to fix it. Collect the required inputs into a collection inside the loop, then invoke the action or subflow once after the loop with the whole collection, or redesign the action to accept collections.

Source. Salesforce Help: Flows Bulkify Actions. Reference implementation: Lightning Flow Scanner, action-call-in-loop

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-022Update triggers must gate on changed valuesHighReliability

What it requires. An after-save flow triggered on update that performs DML must gate its entry on an actual change of the relevant values: trigger conditions set to run only when the record is updated to meet the condition requirements, or an entry formula comparing $Record with $Record__Prior.

Why it matters. Without a change gate, the flow's own record update re-fires the trigger and each firing repeats the DML. Uncontrolled recursion of this kind terminates in a governor limit exception mid-transaction. This is distinct from having entry criteria at all: criteria that never reference prior values do not break the cycle.

How to fix it. Set the trigger to run only when a record is updated to meet the condition requirements, or add an entry formula comparing the fields the flow acts on against $Record__Prior.

Source. Salesforce Architects: Record-Triggered Automation decision guide, Preventing Recursion

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-023Record triggered flows must set trigger orderLowMaintainability

What it requires. Record-triggered flows must set an explicit trigger order value in the start element.

Why it matters. Where multiple flows trigger on the same object and context, execution order without explicit values falls back to creation date: invisible, undocumented, and changed by any rebuild. The Well-Architected data handling pattern is that all record-triggered flows have trigger order values populated. Salesforce recommends spacing values in tens so later flows can be inserted between existing ones.

How to fix it. Assign a trigger order value in the flow's start element, spaced in tens, and document the object's intended sequence.

Source. Salesforce Well-Architected, Easy - Automated: data handling patterns. Also the Salesforce release note: Define the Run Order of Record-Triggered Flows for an Object

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-024No active process builder or workflow processesMediumMaintainability

What it requires. No active Process Builder processes or workflow-era automations should remain in the org. These surface through the Flow API with processType Workflow, CustomEvent, or InvocableProcess.

Why it matters. Process Builder and Workflow Rules are retired generations of automation, superseded by record-triggered flows. Legacy processes run in system context without sharing considerations, fragment an object's automation across tools, and block the one-entry-point model the decision guide prescribes.

How to fix it. Migrate the process to a record-triggered flow (the Migrate to Flow tool covers most patterns), then deactivate and remove the legacy version.

Source. Salesforce Architects: Record-Triggered Automation decision guide. Also Salesforce Well-Architected, Easy - Automated

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-025Flow size and complexity ceilingAdvisoryMaintainability

What it requires. A flow should stay within a workable size. Beyond any of these, logic belongs in subflows: more than 50 elements; cognitive complexity above 15, where each loop or decision counts one and each level of nesting adds a further penalty; cyclomatic complexity above 25, counting loops and decision branches; or any loop nested inside another loop.

Why it matters. Three separate Salesforce sources name the monolithic flow as an anti-pattern: consolidating an object's automation into one mega-flow brings no performance benefit while making refactoring, debugging, and onboarding harder. Nested loops also multiply executed elements per interview, which walks towards the runtime interview limit.

How to fix it. Extract the nested or repeated logic into subflows, each with a single responsibility. Where the complexity is inherent rather than accidental, record why in the flow description so the next person does not mistake it for neglect.

Source. Salesforce Architects: Record-Triggered Automation decision guide, mega-flows. Also Salesforce Well-Architected, Adaptable - Composable and Trusted - Secure. Thresholds from Lightning Flow Scanner: cognitive-complexity (default 15) and excessive-cyclomatic-complexity (default 25).

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-026No hardcoded credentials or secretsHighSecurity

What it requires. Flows must not contain credential material in any value: no API keys, tokens, passwords, or secret-shaped literals in assignments, formulas, or action inputs.

Why it matters. A secret stored in flow metadata is visible to anyone who can open the flow, travels with every metadata retrieval, and lands in version control. Named Credentials exist to hold authentication outside metadata.

How to fix it. Move authentication into Named Credentials or External Credentials and reference them from the action. Rotate any secret that has been present in metadata.

Source. Reference implementation: Lightning Flow Scanner, hardcoded-secret (MIT). Named and External Credentials: Salesforce Help

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-027No hardcoded URLsMediumMaintainability

What it requires. Flows must not hardcode absolute URLs in assignments, formulas, or action inputs. Org URLs change between environments and on My Domain changes; external endpoints belong in Named Credentials or configuration.

Why it matters. A hardcoded URL points at exactly one environment. Sandbox refreshes and My Domain renames silently break links, redirects, and callouts, and the failure surfaces in production rather than in review.

How to fix it. Build org URLs from $Api merge fields or formula resources; hold external endpoints in Named Credentials or Custom Metadata.

Source. Reference implementation: Lightning Flow Scanner, hardcoded-url (MIT)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-028No DML between screens with back navigationHighReliability

What it requires. In screen flows, DML and action elements must not sit on a path between two screens where the later screen allows back navigation. Either disable Previous on the later screen or move the DML after the final screen.

Why it matters. A user pressing Previous re-runs the path, and the DML fires again: duplicate records, double emails, repeated callouts. The user sees nothing wrong at the time; the data shows it later.

How to fix it. Disable Previous on any screen downstream of a DML element, or restructure the flow so all DML follows the final screen.

Source. Reference implementation: Lightning Flow Scanner, duplicate-dml (MIT)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-029No unreachable elementsMediumMaintainability

What it requires. Every element in a flow must be reachable from the start element. Elements with no inbound connector are dead weight and usually the residue of an unfinished change.

Why it matters. Unreachable elements never execute, mislead the next maintainer about what the flow does, and hide half-finished refactors. Their presence means the canvas and the behaviour disagree.

How to fix it. Delete unreachable elements, or reconnect them where the disconnection was the mistake.

Source. Reference implementation: Lightning Flow Scanner, unreachable-element (MIT)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-030Decision default outcome must be deliberateMediumReliability

What it requires. Every Decision element's default outcome must be deliberate: either connected to explicit handling, or clearly marked as an intentional no-op through a renamed outcome label or an element description. Records reaching an unconsidered default outcome pass through the flow silently.

Why it matters. Decision outcomes are evaluated top to bottom, and any record matching no outcome takes the default path. When the default outcome keeps its auto-generated label, carries no description and connects to nothing, there is no evidence the fall-through was considered. Unexpected values then pass through with no action, no error and no log, and the gap surfaces only when a business process is found to have quietly stopped working.

How to fix it. Review each Decision's default path. Where fall-through is intended, rename the default outcome to say so (for example "No action - criteria not met") or explain it in the element description. Where it is not intended, connect the default outcome to explicit handling: an error path, a logging step, or a corrective action.

Source. Salesforce Ben - How to Use Decision Elements and Branching in Salesforce Flow: always configure the Default Outcome as a safety net; every value or scenario that could come through should have a clear path.

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-031Get records should not query all fieldsMediumPerformance

What it requires. Get Records elements must not be configured to store all fields when only specific fields are used downstream. Querying every field retrieves and holds data the flow never touches, which slows the query, inflates the flow interview, and exposes fields the automation has no need to read.

Why it matters. The flow carries data it never uses. At volume that is time and heap spent on nothing, and fields exposed to an automation with no need of them.

How to fix it. Configure the Get Records element to choose specific fields, limiting the query to the fields the flow references.

Source. Lightning Flow Scanner, get-record-all-fields

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-032No unused variablesLowMaintainability

What it requires. Every variable declared in a flow must be referenced by at least one element, formula, or input/output assignment. Unused variables accumulate as clutter and mislead the next person about what the flow consumes and produces.

Why it matters. Dead variables make the flow lie about its own inputs and outputs, so every later change starts with working out which of them are real.

How to fix it. Delete variables that nothing references. If a variable is reserved for a planned change, record that in the flow description instead.

Source. Lightning Flow Scanner, unused-variable

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-033Inactive flows should be removedLowMaintainability

What it requires. Flow definitions with no active version should be deleted or archived rather than left in the org. The scanner project notes they can still cause unintended record changes during testing or be invoked as subflows, and they sit as clutter between an admin and the automation that matters.

Why it matters. An org full of dead definitions makes every audit, deployment and impact assessment slower, and a definition that looks dormant is not always inert.

How to fix it. Delete flow definitions that are no longer needed, exporting the metadata first where a record is required.

Source. Lightning Flow Scanner, inactive-flow

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-034Use auto layoutAdvisoryMaintainability

What it requires. Flows should use auto-layout rather than the freeform canvas. Auto-layout keeps element arrangement consistent, so the next person reads the logic rather than the drawing.

Why it matters. Freeform canvases drift into layouts only their author can follow, and reading time is maintenance cost.

How to fix it. Switch the flow canvas to auto-layout and confirm the arrangement remains readable.

Source. Lightning Flow Scanner, missing-auto-layout

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-035Prefer transform over assignment loopsAdvisoryPerformance

What it requires. A Loop element whose body only assigns values onto each item should use a Transform element instead. Transform operates on the collection in bulk, removing per-item iteration and the complexity that comes with it.

Why it matters. Element-by-element iteration is the slow path the platform has already replaced. Transform does the same work in bulk with less to read and less to maintain.

How to fix it. Replace the loop and its assignments with a Transform element mapping the source collection to the target collection.

Source. Lightning Flow Scanner, transform-instead-of-loop

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-036Prefer records over ID stringsAdvisoryMaintainability

What it requires. A flow that receives a record Id as a text variable and immediately queries the record should receive the record itself where the caller has it. Passing the Id forces an extra Get Records and loses the type information the platform provides.

Why it matters. An Id-only handoff throws away what the caller already knew and buys it back with another query.

How to fix it. Change the input variable to a record variable and pass the record from the calling context. Keep an Id-based input only where callers cannot supply the record.

Source. Lightning Flow Scanner, record-id-as-string

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

FL-037No copy of element API namesLowBetaMaintainability

What it requires. Flow elements must not retain copy-paste API names of the form Copy_1_of_X. When an element is duplicated the API name should be updated to describe what the copy does.

Why it matters. A copied element keeps a name that describes its origin rather than its purpose, so the next person reads the drawing rather than the logic. It is also a reliable signal that a flow was built by duplication without review.

How to fix it. Rename the element to describe what it does. If the duplicate was accidental, remove it.

Source. Lightning Flow Scanner, unclear-api-naming (CopyAPIName). Rule id unclear-api-naming, category layout.

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

Revenue Cloud Advanced

15 rules, and 6 in beta

RCA Pricing & Catalog Rules v1.0.3. Open a rule for what it requires, why it matters, how to fix it, and where it comes from. A rule marked beta runs and is reported but is not charged for. Tell us whether a rule is worth checking — votes and comments both go to a person, and we publish what we change.

RC-001Hardcoded constants in pricing expressionsMediumBetaPricing Integrity

What it requires. A numeric literal (a rate, a price, an uplift) sits inside a pricing element formula or parameter instead of a decision table or price book reference.

Why it matters. [reasoned from platform semantics] A literal in a step lives in versioned procedure metadata: changing it is a builder-access version edit and re-activation, invisible to data governance, and duplicated copies drift silently. Finance reads one price in the catalog while the engine charges another.

How to fix it. Move the value into the decision table or price source the element should reference; the number becomes data with an audit trail.

Source. Salesforce Help: Use Pricing Elements in Pricing Procedures (semantics; mechanism reasoned)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-002Condition ladder where a decision table belongsMediumBetaPerformance & Scale

What it requires. A sequence of conditional elements enumerates cases (per-segment rates, per-product uplifts) that a single decision table lookup would serve.

Why it matters. [reasoned; corroborated by practitioner literature] Each ladder step is a sequential evaluation inside the procedure's runtime budget (one-minute default, two-minute maximum for a pricing procedure; a discovery procedure gets 10 seconds by default and 60 at most) and an element against the 130-per-version cap; a decision table is one compiled, indexed lookup - the platform's stated purpose for them. Adding a tier becomes a row plus refresh, not a version edit. Two guards on the fix: a decision table answers from its last refresh, so the conversion must arrive WITH refresh discipline (see RC-008) or it introduces a stale-price failure the ladder never had; and trivial logic stays inline - a single condition is not a ladder, and converting it buys nothing.

How to fix it. Collapse the ladder into one decision table and one lookup element.

Source. Kavaliro: RLM Pricing Procedures (practitioner); Salesforce Pricing Limits (budgets)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-003Ad hoc custom fields mapped into the pricing contextLowBetaMaintainability

What it requires. Context mappings pull unconventional custom fields or loosely named variables instead of standard pricing-context attributes.

Why it matters. [reasoned] The context definition is the contract between quote data and the engine: ad hoc mappings couple pricing to unstable schema, faults surface at quote time, and clutter obscures the release-time diff the extension mechanism exists to carry.

How to fix it. Map standard attributes where they exist; name and document any custom mapping as deliberately as a public interface.

Source. Salesforce KB 004259656 (adjacent extension guidance; mechanism reasoned)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-004Expression set version sprawlLowBetaMaintainability

What it requires. A procedure or model carries many inactive versions or undated drafts ahead of the active version.

Why it matters. [reasoned; live-observed 27 Aug 2026] The active version is one status flip among lookalikes: people debug the wrong version, and drafts read as deployed. In production the same state is a heavier signal than in a sandbox workshop - severity is environment-modulated by design. Two allowances: a draft ahead of the active version with a FUTURE start date is deliberate staging, not sprawl - versions carry effective-date windows for exactly that; and numbering gaps alone prove nothing, because cross-org deployments renumber versions. The signal is inactive volume plus undated drafts ahead of active.

How to fix it. Retire superseded versions; keep one active optimised version and at most one deliberate draft.

Source. Salesforce Help: Build Your Pricing Procedures (versioning semantics; mechanism reasoned)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-005Manual arithmetic standing in for aggregation elementsMediumBetaPricing Integrity

What it requires. Assignment arithmetic re-derives group totals that a GroupingAndAggregatePricing element should compute.

Why it matters. [reasoned] The aggregation element computes group totals once inside the waterfall; hand-rolled copies diverge when one is edited, and the Price Waterfall's per-element explanation degrades into opaque assignments - discarding the debuggability the platform sells. Two documented carve-outs where manual arithmetic is the only option and is NOT a defect (Trailhead, advanced price management): aggregation elements do not support derived products, and direct rollup to quote or order headers is not supported. Line-level unit arithmetic and those two cases pass this check.

How to fix it. Replace the arithmetic with the aggregation element and let dependent elements read its output.

Source. Salesforce Help: Use Pricing Elements in Pricing Procedures (element vocabulary; mechanism reasoned)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-006Context definition with both ClonedFrom and InheritedFromHighPricing Integrity

What it requires. A context definition carries values in both ClonedFrom and InheritedFrom (Tooling API fields).

Why it matters. [doc] Salesforce's own words: such a definition "can result in unexpected pricing errors and should be recreated", and "the InheritedFrom field should be blank if ClonedFrom is populated" (KB 004259656). The platform's default-procedure error path separately requires extension-not-clone lineage (KB 002183049). Two contradictory lineages; the sanctioned remedy is recreate, not repair.

How to fix it. Recreate the definition as a clean extension of the standard, then re-associate its procedures.

Source. Salesforce KB 004259656; KB 002183049

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-007Cloned context definition missing standard mappingsHighPricing Integrity

What it requires. A custom context definition was cloned rather than extended and lacks mappings the standard definition has since gained.

Why it matters. [doc] Extending a standard definition carries automatic upgrades and a Sync Now option, so mappings added by later releases arrive on their own; a clone of a standard definition gets "no automatic upgrades" (Salesforce Help, Clone a Context Definition). The exception is the thing this check keys on: a clone of an already-extended definition keeps its upgrades only when Preserve Inheritance was enabled, which is exactly the ClonedFrom-populated-with-InheritedFrom-empty state. A mapping that never arrived means the attribute is silently null in context, so every element referencing it no-ops: wrong price, no error. Separately, a definition carrying BOTH lineages "can result in unexpected pricing errors and should be recreated" (KB 004259656) - that is RC-006.

How to fix it. Recreate as an extension, or diff against the current standard and add the missing mappings deliberately.

Source. Salesforce Help: Clone a Context Definition (clone vs extend upgrades); Salesforce KB 004259656 (lineage)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-008Stale decision tableHighPricing Integrity

What it requires. A decision table's source object rows were modified after the table's LastSyncDate.

Why it matters. [doc] A decision table is a compiled snapshot: it does not update when source data changes, and answers from the old compilation until refreshed (Salesforce Help). Modifications during a refresh may not be integrated, and an invocable Refresh Action exists for automation - so unrefreshed price rows are a standing wrong-price mechanism, not a hypothetical. In a sandbox, state the sandbox refresh date alongside: staleness predating it describes nothing.

How to fix it. Refresh the table now, and wire the Decision Table Refresh Action into whatever automation changes the source rows.

Source. Salesforce Help: Refresh a Decision Table; Decision Table Refresh Action

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-009Free-text attribute driving pricingMediumBetaPricing Integrity

What it requires. A price-impacting product attribute (ProductAttributeDefinition.IsPriceImpacting) has a text data type with no picklist.

Why it matters. [practitioner-corroborated + reasoned] Pricing matches on attribute values: free text admits case, spacing and typo variants that miss exact-match lookups, so the adjustment silently never applies and a fallback price is charged. Corroborated across practitioner sources (arraytrail; Applikon); CML's keep-domains-small guidance states the same principle for configuration. Official Help pin outstanding.

How to fix it. Convert the attribute to a picklist so every value is matchable by construction.

Source. Practitioner (arraytrail; Applikon), corroborated; official pin pending

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-010No default pricing procedure fallbackHighPricing Integrity

What it requires. The org's recipe/plan routing lacks a valid default pricing procedure for quotes that match no rule.

Why it matters. [doc] The platform fails such quotes at quote time with a named error: "The default pricing procedure must be associated with a context definition that's an extension of SalesTransactionContext__stdctx" (KB 002183049). Sellers are blocked in the moment of selling.

How to fix it. Set a default pricing procedure whose context definition extends the standard, so every quote prices deterministically.

Source. Salesforce KB 002183049

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-011Pricing procedure near the element ceilingMediumPerformance & Scale

What it requires. An active procedure version's element count approaches the documented default of 130 elements per version (raisable to a documented maximum of 200 by a Salesforce support case, assessed individually for performance impact).

Why it matters. [doc] At the cap the next pricing change fails with a hard error - "Delete a pricing element and try again" (KB 005385232) - mid-change, with a support request as the only relief: the case goes to the Revenue Cloud Feature Activation team and is assessed individually for performance impact. The ceiling is documented rather than open-ended: Salesforce Pricing Limits gives pricing elements per pricing procedure as default 130, maximum 200, and the same page caps a pricing procedure's runtime at a one-minute default and a two-minute maximum, which tightens with element count. Findings state the default, the documented maximum and the support-case path, and never promise that a particular increase will be granted.

How to fix it. Consolidate redundant elements, split map-heavy elements, move mapping logic into decision tables, or route strategies through a plan. Where the design genuinely cannot be simplified, the support case is the documented path to a higher limit, up to 200.

Source. Salesforce KB 005385232; Salesforce Pricing Limits

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-012SKU proliferation standing in for attributesAdvisoryCoverage & Adoption

What it requires. Near-duplicate products differ only by tokens an attribute should carry (size, term, tier), multiplying the catalog.

Why it matters. [practitioner: Cloud Giants] "Companies have long been guilty of SKU proliferation" - each variant-as-SKU multiplies every downstream artefact (price rows, selling models, components, table rows keyed by product) into a multiplicative maintenance surface, where attributes carry the same variance as data through one product.

How to fix it. Model the variance as attributes on one product; retire the variant SKUs as they fall out of quotes.

Source. Cloud Giants: RCA products guide

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-013Catalog hygiene floorLowMaintainability

What it requires. Active products lack descriptions or drift from any naming convention.

Why it matters. [practitioner: Cloud Giants] "Define a consistent Product Name, SKU and Code convention. Populate Product Descriptions." Names and descriptions are the catalog's human interface - quoting UI, approvals and reports surface them; blanks invite mis-selection and unreviewable approvals.

How to fix it. Populate descriptions and settle one naming convention; enforce it at product creation.

Source. Cloud Giants: RCA products guide

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-014Pricing fields inside a constraint modelHighPricing Integrity

What it requires. CML source references pricing fields such as ListPrice or NetUnitPrice.

Why it matters. [doc] "Pricing fields, such as ListPrice, NetUnitPrice, and others, are not supported in CML and should not be used in constraint models" (CML Best Practices). The constraint engine does not evaluate pricing context, so such constraints silently fail to enforce - configurations pass that should not.

How to fix it. Remove pricing references from the model; express commercial limits through pricing procedures and adjustments where they are evaluated.

Source. Salesforce CML Best Practices (developer guide)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-015Cardinality unbounded in model and master dataMediumPerformance & Scale

What it requires. Relations carry no cardinality in CML AND the catalog's component rows carry no Min/MaxQuantity or required flags - nothing bounds the solver anywhere.

Why it matters. [doc + practitioner: Khaled McGonnell, 27 Aug 2026] Cardinality belongs in product master data (ProductRelatedComponent, ProductComponentGroup), which the configurator enforces; CML should not duplicate it. Where NEITHER declares bounds, the solver enumerates combinations it cannot bound ("specify the smallest required cardinality... to avoid testing unneeded combinations" - CML Best Practices), and an empty or gutted bundle is a legal configuration.

How to fix it. Set Min/MaxQuantity and required flags on component rows and group minimums in the catalog; reserve CML cardinality for what master data cannot express.

Source. Salesforce CML Best Practices; practitioner mechanism attributed (Khaled McGonnell, 27 Aug 2026)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-016Quantity fields driving component creationHighPerformance & Scale

What it requires. CML uses lineItemQuantity or ItemEndQuantity to create components rather than treating them as read-only.

Why it matters. [doc + practitioner: Khaled McGonnell, 26 Aug 2026] "Treat lineItemQuantity and ItemEndQuantity as read-only... Drive component creation by cardinality, not by attribute references" (CML Best Practices). A cardinality constraint tells the solver the valid range directly; rule-driven creation forces it to enumerate and test combinations, and the cost compounds with permutation growth - practitioner-confirmed as disastrous for performance.

How to fix it. Declare the component range as cardinality; use quantity fields only in calculation and evaluation rules.

Source. Salesforce CML Best Practices; practitioner mechanism attributed (Khaled McGonnell, 26 Aug 2026)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-017Conflicting setdefault rules on one targetMediumPricing Integrity

What it requires. Multiple conditional setdefault rules target the same assignment.

Why it matters. [doc + reasoned] "When multiple setdefault rules target the same assignment in the RHS, evaluations can conflict" and "only the last rule will reliably evaluate" (CML Best Practices) - earlier rules are not merely lower priority, they are unreliable. The configured default depends on evaluation order the modeller does not control, and an edit elsewhere can flip it.

How to fix it. Consolidate the conditional logic into a single derived variable with one setdefault.

Source. Salesforce CML Best Practices (developer guide)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-018Relations declared against constraint orderLowPerformance & Scale

What it requires. Relation declarations do not follow the documented LHS-first ordering for the constraints that use them.

Why it matters. [doc] "Order of relations matter for constraint evaluation. Specify the relations used in the LHS of the constraints first, followed by those in the RHS" (CML Best Practices). That sentence is the strongest published claim: Salesforce states that ordering matters for constraint evaluation, and no measurements of the cost exist publicly. Detection requires parsing, not grep - build cost noted.

How to fix it. Reorder relation declarations to match constraint LHS-then-RHS usage.

Source. Salesforce CML Best Practices (developer guide)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-019Discovery and pricing procedures on different context definitionsHighPricing Integrity

What it requires. The active discovery procedure and pricing procedure are associated with different context definitions.

Why it matters. [doc] The platform fails product-add at quote time with a named error: "Ensure that the discovery procedure and pricing procedure are associated with same context definition" (KB 002188066). A configuration join detects before a seller does.

How to fix it. Re-associate the discovery procedure with the pricing procedure's context definition (deactivate, update, reactivate per the KB).

Source. Salesforce KB 002188066

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-020Decision table compiled from an empty datasetHighPricing Integrity

What it requires. An active decision table's source object holds zero rows.

Why it matters. [doc via snapshot semantics + payload schema] A table compiled from nothing returns no match for every lookup, so every dependent element takes its no-result branch (the step schema's noResultExplainerTemplate is exactly that path) and adjustments silently never apply. Where the empty table is unadopted Salesforce-standard machinery, report as Coverage & Adoption instead - the standard-vs-custom cut decides defect versus signal.

How to fix it. Populate and refresh the source, or retire the table and the elements that read it.

Source. Salesforce Help: Refresh a Decision Table (snapshot semantics)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.

RC-021Constraint model out of sync with product definitionsMediumPricing Integrity

What it requires. A constraint model has not been synced since its products' definitions changed in Product Catalog Management.

Why it matters. [doc] Salesforce ships a sync mechanism because CML encodes product structure at authoring time: "Sync product definition changes from Product Catalog Management (PCM) to the constraint modeling language (CML)... to make sure that the CML reflects the latest product definition." The failure consequence - the configurator enforcing yesterday's product, valid configurations rejected and invalid accepted - is inferred from that mechanism and is stated as inference: Salesforce documents the sync, not the failure. The stale-tables mechanism at the configurator layer. Child-page pin outstanding; parent page cited.

How to fix it. Run the constraint model sync after product definition changes, and put the sync into the change process.

Source. Salesforce Help: Rules and Constraints in Configurator (sync section)

Is this rule worth checking?

Votes and comments are published here. We read them, and we publish what we change with the reasoning — a vote does not move a rule on its own.