Chalky · Rule registry

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

77 rules across three scans, naming the Salesforce documentation or practitioner guidance behind each one where an authoritative external source exists, plus 11 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: 31 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.

31 August 2026AG-017newA model call inside a loop
31 August 2026AG-023newConversation and prompt data retained past the stated policy
31 August 2026AG-021newA response limit that truncates rather than fails
31 August 2026AG-020newAn answer that can come back short, silently
31 August 2026AG-018newThe active agent version is not the edited one
31 August 2026AG-022newA path that can complete having done nothing
31 August 2026AG-025newUntrusted inbound text reaches a grounded prompt
31 August 2026AG-017newA model call inside a loop
31 August 2026AG-019newNo defined behaviour when an action fails
31 August 2026AG-030newA side-effecting action with no confirmation
31 August 2026AG-031newA non-idempotent action behind a retry
31 August 2026AG-026newOverlapping or duplicative actions
31 August 2026AG-024newReasoning budget spent on retrieval
31 August 2026AG-033newInstructions that cannot be followed from the model's seat
31 August 2026AG-027newBuried answers
31 August 2026AG-028newMissing negative documentation
31 August 2026AG-029newVocabulary mismatch
31 August 2026AG-032newNo regression set for a topic
31 August 2026AG-007newDegenerate cardinality on a grounded field
31 August 2026AG-008newFree-text grounding with high value dispersion
31 August 2026AG-001newOrphaned action
31 August 2026AG-002newTopic with no example utterances
31 August 2026AG-015newScope claims a domain the grounding does not span
31 August 2026AG-004newGrounding data invisible to the agent's running user
31 August 2026AG-005newThe grounding source is absent or empty
31 August 2026AG-010newStale grounding records
31 August 2026AG-003newGrounding reference to a field that does not exist
31 August 2026AG-016newUnbounded grounding scope
31 August 2026AG-011newKnowledge articles archived, draft or stale while still retrievable
31 August 2026AG-009newDuplicates in the retrieval set
31 August 2026AG-006newNull rate above threshold on a grounded field
30 August 2026FL-037changedNo copy of element API names
30 August 2026FL-019changedFlow must not run in system mode without sharing
30 August 2026SF-flow-test-coveragedeclinedSF-flow-test-coverage
30 August 2026FL-032changedNo unused variables
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-010changedVariable naming convention
30 August 2026FL-002changedFlow naming convention

Showing the 40 most recent of 98 recorded changes.

Agentforce

26 rules, and 4 in beta

Salesforce Agentforce Readiness Rules v1.0.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.

AG-001Orphaned actionLowGrounding Integrity

What it requires. An agent action that is defined but attached to no topic, so no agent can ever reach it.

Why it matters. An orphaned action is configuration that looks like capability. It appears in the action list, it is counted when someone asks how much the agent can do, and it never runs. The planner routes through topics, so an action outside every topic is unreachable by construction rather than by accident.

How to fix it. Attach the action to the topic that should own it, or delete it. Leaving it in place makes the agent look more capable than it is.

Source. Agentforce planner model: actions are reached through topics

AG-001 on its own page

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.

AG-002Topic with no example utterancesMediumGrounding Integrity

What it requires. A topic carrying no example utterances, leaving the planner nothing to match a user request against.

Why it matters. Routing is the planner deciding which topic a request belongs to. With no examples the decision is made on the topic name and scope alone, so requests land in the wrong topic or in none. This fired five times on the first prototype run, making it the most common finding in that run.

How to fix it. Add example utterances in the words customers actually use, not the words the topic is named after.

Source. Prototype run against a live org, 30 August 2026 (5 of 10 findings)

AG-002 on its own page

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.

AG-003Grounding reference to a field that does not existHighGrounding Integrity

What it requires. A merge field or grounding reference naming a field that is absent from the org.

Why it matters. The agent does not error on a missing field, it substitutes silently, so the prompt reaches the model with a hole in it and the answer is produced from what remains. Common after a migration or a managed-package change, and invisible in the output.

How to fix it. Repoint the reference at the field that replaced it, or remove the reference and the sentence that depended on it.

Source. Prompt template merge-field resolution behaviour

AG-003 on its own page

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.

AG-004Grounding data invisible to the agent's running userHighGrounding Integrity

What it requires. Field-level security or sharing hides grounded data from the user the agent runs as, so the agent answers from nothing.

Why it matters. The agent inherits its running user's visibility. Where sharing or field-level security removes a record or a field, the grounding returns empty and the model answers anyway, fluently, from whatever remains. Nothing in the output distinguishes this from a correct answer. With AG-016 established, this is the bound on every downstream quality claim rather than one check among many.

How to fix it. Check the running user's profile and sharing against every object and field the agent grounds on. Where access is deliberately withheld, remove the grounding rather than leaving the agent to answer around it.

Source. Agentforce running-user model; our grounding quality specification v1

AG-004 on its own page

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.

AG-005The grounding source is absent or emptyHighGrounding Integrity

What it requires. An action pointed at a corpus that is not enabled, or at an object holding no records.

Why it matters. An empty source reads exactly like a source with nothing relevant in it. The agent answers from adjacent material and sounds no less certain. This fired on the first prototype run against a real org, which is why it leads this family rather than sitting inside it: the failure is not rare and it is not visible.

How to fix it. Enable the corpus, or point the action at the source that actually holds the content. If neither, remove the action.

Source. Prototype run against a live org, 30 August 2026 (fired first pass)

AG-005 on its own page

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.

AG-006Null rate above threshold on a grounded fieldMediumGrounding Quality

What it requires. A field the agent reads is empty on a large enough share of records that the answer is usually produced without it.

Why it matters. A field that exists and is mostly empty grounds nothing. The agent still reads it, still produces an answer, and the answer is built from whatever else was in the prompt.

How to fix it. Populate the field, or stop grounding on it and say in the topic scope that the agent cannot answer from it.

Source. Our grounding quality specification v1, section 3

AG-006 on its own page

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.

AG-007Degenerate cardinality on a grounded fieldLowGrounding Quality

What it requires. One value dominates a grounded field so heavily that the field distinguishes nothing.

Why it matters. A field where 98% of records share a value carries almost no information, but it looks like a populated field to anyone reviewing the configuration. The agent uses it and the answers do not vary with it.

How to fix it. Ground on the field that actually varies, or accept that answers cannot be differentiated on this dimension and say so in the scope.

Source. Our grounding quality specification v1, section 3

AG-007 on its own page

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.

AG-008Free-text grounding with high value dispersionMediumGrounding Quality

What it requires. A free-text field grounded into a prompt where values are so dispersed that retrieval cannot rank them.

Why it matters. Free text with no controlled vocabulary gives retrieval nothing to match on, so what surfaces is close to arbitrary and varies between otherwise identical questions.

How to fix it. Introduce a controlled field alongside the free text and ground on that, keeping the free text for the human reader.

Source. Our grounding quality specification v1, section 3

AG-008 on its own page

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.

AG-009Duplicates in the retrieval setMediumGrounding Quality

What it requires. The same question is answered by more than one record, so the answer depends on which surfaces first.

Why it matters. Duplicate or near-duplicate sources make the agent non-deterministic in a way nobody can see from the configuration. Two users ask the same thing and get different answers, both defensible, neither reproducible.

How to fix it. Merge or retire the duplicates, and make one record canonical for each question.

Source. Our grounding quality specification v1, section 3

AG-009 on its own page

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.

AG-010Stale grounding recordsMediumGrounding Quality

What it requires. The last-modified distribution of a grounded source is skewed old enough that the agent is citing retired reality.

Why it matters. Staleness is invisible in the output: the agent cites an old record as confidently as a current one. It fired on the first prototype run. Note this is a measurement of the business, not of a sandbox - a refreshed copy carries the refresh date, not the record's real age.

How to fix it. Review and retire the stale records, or narrow the grounding to a recency window the business actually maintains.

Source. Prototype run against a live org, 30 August 2026

AG-010 on its own page

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.

AG-011Knowledge articles archived, draft or stale while still retrievableMediumGrounding Quality

What it requires. Knowledge articles in a non-published state, or long unreviewed, that the agent can still retrieve and quote.

Why it matters. An archived article is a decision that it should no longer be relied on. If retrieval can still reach it, that decision has been recorded and not enforced, and the agent will quote it as current.

How to fix it. Exclude non-published states from the retrieval scope, and set a review cadence for the rest.

Source. Salesforce Knowledge article lifecycle states

AG-011 on its own page

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.

AG-015Scope claims a domain the grounding does not spanMediumCoverage & Adoption

What it requires. A topic's stated scope promises to answer about a domain that its grounding does not cover.

Why it matters. The scope is what the planner routes on and what a reader takes as the agent's remit. Where it is broader than the grounding, requests route in correctly and are answered from nothing relevant. This is an irreducibly semantic check and is reported as a judgement rather than a measurement.

How to fix it. Narrow the scope to what the grounding supports, or widen the grounding to match the promise.

Source. Our grounding quality specification v1, section 3

AG-015 on its own page

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.

AG-016Unbounded grounding scopeHighGrounding Integrity

What it requires. An action that resolves its target at runtime, so the grounding surface is everything the running user can see rather than a declared field list.

Why it matters. Actions such as queryRecords, identifyObject and getRecordFieldsAndValues decide what to read when they run. There is no field list to review, so the honest description of what the agent is grounded on is the whole visible estate. That is the finding: not that a particular field is exposed, but that the question "what is this agent grounded on?" has no bounded answer.

How to fix it. Replace runtime resolution with a declared grounding target where the use case allows. Where it does not, treat the running user's visibility as the grounding scope and review it as such.

Source. Our grounding quality specification v1, section 5

AG-016 on its own page

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.

AG-017A model call inside a loopHighCost & Efficiency

What it requires. A prompt template or agent action invoked inside a loop, once per record, where the platform offers a bulk or batched path.

Why it matters. Metered per action, the naive shape is expensive in a way that does not show up until the bill. At 20 Flex Credits an action, a per-record call across a 5,000-row job is a $500 line item where a batched design costs a fraction of it. Measured on the same shape, 109 evaluations through one batch took about 11.6 minutes rather than 36 times the duration of a single call, which is why batching is the remedy rather than an optimisation.

How to fix it. Move the call outside the loop and pass the collection, or use the platform's batched path.

Source. Salesforce Flex Credits pricing; our batch runner implementation

AG-017 on its own page

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.

AG-018The active agent version is not the edited oneHighBetaReliability

What it requires. An agent, topic, action or prompt template has been changed since the version that is actually live, so the org's behaviour and its configuration disagree.

Why it matters. A save that succeeds is not a deployment, and nothing downstream tells the two apart: an updated component can sit in a draft for days while the active version keeps serving, and every run in between looks healthy. The consequences are silent by construction - an old version running past a ceiling the new one was written to clear, or stale configuration in every delivered output - because the deploy step reported success. The check is to read the active version, never to infer it from a successful save. On prompt templates the platform states this directly, exposing an active version identifier alongside each version's own.

How to fix it. Compare the active version against the latest edited version for every agent, topic and template, and republish or revert so they agree.

Source. Root-cause records, August 2026; Salesforce prompt template version metadata

AG-018 on its own page

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.

AG-019No defined behaviour when an action failsHighReliability

What it requires. A topic whose instructions say nothing about what happens when an action errors, times out or returns empty, and an action path with no fault handling behind it.

Why it matters. Unhandled failure in an agent does not stop the conversation, it changes the answer. The model continues without the data and produces something plausible. The same shape upstream is worse: a run left in an intermediate state can be invisible to every downstream stage at once - the report, the delivery and the chase queue alike - so nobody is ever told. On the org this was written against, not one of twenty-one instructions mentioned failure at all.

How to fix it. Add a fault path to every flow-backed action, and state in the topic instructions what the agent should say when an action returns nothing.

Source. Our defect handling standard, 16 August 2026

AG-019 on its own page

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.

AG-020An answer that can come back short, silentlyMediumBetaReliability

What it requires. A prompt template or action asked for a set of things - every case, each product, all the reasons - with no structured output and no completeness check, so a response missing items reads exactly like a complete one.

Why it matters. An evaluator that returns a schema keyed by rule code cannot omit a rule without failing validation. With no such guard, coverage drift is invisible: rules go unevaluated behind a plausible-looking total, and nothing distinguishes a run that checked everything from one that quietly checked less. With it, a run either carries the expected rows for every subject - 1,147 checks of 1,147 - or it fails outright. A generation with no output schema has no equivalent guard, and a short answer is a well-formed one.

How to fix it. Give the template an output schema listing what must come back, so an incomplete answer fails instead of reading as complete.

Source. Our evaluator coverage design, August 2026

AG-020 on its own page

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.

AG-021A response limit that truncates rather than failsMediumBetaReliability

What it requires. A generation whose length limit is low enough that answers are cut off, with no indication to the reader that anything was lost.

Why it matters. A response cut off at max_tokens presents as a model failure rather than a limit, and costs real time to diagnose, because a truncated response is a well-formed one - it ends, it reads, and nothing marks the point where it stopped. It is the same failure class as AG-020 and worth keeping separate because the fix is a number rather than a schema.

How to fix it. Raise the limit to fit the longest legitimate answer, or have the template return a structured result whose completeness can be checked.

Source. Root-cause record, max_tokens truncation, August 2026

AG-021 on its own page

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.

AG-022A path that can complete having done nothingHighReliability

What it requires. An agent path where the do-nothing outcome and the success outcome are indistinguishable to everyone downstream: no signal, no counter, no field that would look different.

Why it matters. This is the failure that reports itself as success, and the shapes recur: a storage path column empty on every record while the process reads as though files were stored; a discounted order that takes the payment branch, reports completion and never starts what was ordered; a double-encoded column that makes a discount unreachable with nothing going red anywhere. It is semantic and hard, and it describes the failures nobody reports.

How to fix it. For each path, name the field that would look different if it had worked, and assert on it. If there is no such field, that is the defect.

Source. Standing check: if this silently did nothing, what would look different?; root-cause records, August 2026

AG-022 on its own page

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.

AG-023Conversation and prompt data retained past the stated policyHighBetaSecurity

What it requires. The org's own retention promise and what the platform actually keeps disagree - transcripts, prompts, grounded record values and audit rows.

Why it matters. A stated retention of "none" on a connection record says nothing about what the orchestration around it keeps. Where that platform logs every step's input and output, a single execution can hold the same customer's pricing metadata three times over, alongside their client name and instance URL: a promise made in one system and not kept by another. Note the audit surface is not in Salesforce core, so the check reaches beyond the org's own configuration.

How to fix it. Reconcile the published retention policy against what each platform in the path actually stores, and change whichever is wrong - usually the system, sometimes the promise.

Source. Retention root-cause record, August 2026; Einstein Trust Layer audit documentation

AG-023 on its own page

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.

AG-024Reasoning budget spent on retrievalMediumCost & Efficiency

What it requires. A large or high-effort model configured for a task that is lookup or formatting, where a smaller model is equivalent.

Why it matters. Retrieval earns no reasoning budget; judgement does. Where an action is fetching or reformatting, a larger model costs more per call and returns nothing extra. With actions metered individually the difference is measurable rather than theoretical. The template's own type says which shape it is.

How to fix it. Move lookup and formatting templates to the smaller model and keep the larger one where a verdict is being formed.

Source. Our LLM budget ruling; Salesforce Flex Credits metering

AG-024 on its own page

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.

AG-025Untrusted inbound text reaches a grounded promptHighSecurity

What it requires. Text that a stranger can write - web-form fields, inbound email bodies, case descriptions, chat transcripts - is grounded into a prompt for an agent that can take actions or emit outbound links.

Why it matters. ForcedLeak (CVSS 9.4, Noma Labs, September 2025) submitted instructions through Web-to-Lead which executed later during an ordinary employee interaction and exfiltrated CRM data. Salesforce patched it - re-securing the domain and enforcing a URL allowlist on agent output - and that patch is the vendor's own evidence that the platform did not prevent it. The documentation describes prompt defence as heuristics that reduce the odds, not eliminate them. The check is not whether the Trust Layer is on; it is which untrusted fields reach a grounded prompt and what the agent can do once they are there.

How to fix it. Separate untrusted inbound fields from grounded prompts, or strip them to a controlled vocabulary before grounding. Where they must be grounded, restrict the agent's action scope on that surface.

Source. ForcedLeak, Noma Labs, September 2025 (CVSS 9.4); Salesforce Trust Layer documentation

AG-025 on its own page

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.

AG-026Overlapping or duplicative actionsMediumMaintainability

What it requires. Two or more actions with the same target and overlapping descriptions, reachable from the same agent.

Why it matters. More tools do not always lead to better outcomes, and overlapping tools distract an agent from pursuing efficient strategies. This is a cited behavioural claim rather than a tidiness preference, and it comes with a fix: namespacing, or removing the duplicate.

How to fix it. Remove the duplicate, or namespace the two so their descriptions no longer compete for the same request.

Source. Anthropic tool-design guidance on overlapping tools

AG-026 on its own page

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.

AG-027Buried answersMediumCoverage & Adoption

What it requires. An article whose answer to its own title sits deep in the body, so retrieval returns the background instead.

Why it matters. Retrieval pulls passages, not documents. Where the answer is in paragraph nine and the opening is context, what reaches the model is the context. This is structure rather than judgement, which is what makes it detectable.

How to fix it. Move the answer to the top of the article and leave the background beneath it.

Source. Support-agent knowledge base literature

AG-027 on its own page

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.

AG-028Missing negative documentationMediumCoverage & Adoption

What it requires. No content stating that a thing is unsupported, so the agent constructs a plausible answer from adjacent material.

Why it matters. With nothing saying a feature does not exist, an agent will often construct a plausible answer from adjacent material - which is a promise of something that does not exist, made to a customer, in writing. A coverage gap with a commercial consequence attached.

How to fix it. Write the negative cases down. An article saying plainly that something is not supported is worth more than one describing what is.

Source. Support-agent knowledge base literature

AG-028 on its own page

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.

AG-029Vocabulary mismatchLowCoverage & Adoption

What it requires. An article that never uses the phrasing customers use, so it loses retrieval to a less relevant one that does.

Why it matters. Retrieval matches language, not intent. An article written in internal vocabulary is invisible to the request it answers, and the request is answered by something worse.

How to fix it. Add the customer's phrasing to the article - as a heading, an alternate title, or keywords - without rewriting the substance.

Source. Support-agent knowledge base literature

AG-029 on its own page

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.

AG-030A side-effecting action with no confirmationHighSecurity

What it requires. An action that writes, sends, refunds, cancels or deletes, reachable by the planner with no confirmation step and no human in the loop.

Why it matters. To the planner an irreversible action is just another tool. The interesting version of this check is not "no confirmation anywhere" but "no confirmation on the irreversible ones specifically". On the org this was written against, exactly one of twenty-nine actions required confirmation - the record write - while an action that modifies automation metadata and two that send outbound to a third party carried none.

How to fix it. Set confirmation on every action whose effect leaves the org or cannot be undone, and review the default on any action installed by a package.

Source. General agent design practice; probe of a live org, 31 August 2026

AG-030 on its own page

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.

AG-031A non-idempotent action behind a retryHighReliability

What it requires. An action that is not safe to run twice, on a path that can run it twice - a retry, a re-planned step, or a user repeating themselves.

Why it matters. Planners retry, and users repeat themselves. Where the action creates, sends or moves money, the second run is a second real-world effect. The remedy is an idempotency key derived from the run itself, so a retry cannot double-charge or double-refund; without one the failure is silent and expensive.

How to fix it. Give the action an idempotency key derived from the request rather than the attempt, or gate it behind a confirmation the planner cannot repeat.

Source. Our refund model implementation

AG-031 on its own page

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.

AG-032No regression set for a topicMediumMaintainability

What it requires. A topic with no test utterances, or with utterances that have not been re-run since the topic last changed.

Why it matters. Salesforce ships Testing Center and vendors sell generated utterance sets, but nobody checks whether the set was run after the last change. This is the agent form of the standard we hold ourselves to: the tests changed in the same edit as the behaviour, or they prove nothing. On the org this was written against, every scorer was a shipped predefined one and there was not a single custom evaluation.

How to fix it. Write utterances for each topic and re-run them as part of any change to that topic, not on a schedule.

Source. Salesforce Testing Center; our standing check that tests change with the behaviour

AG-032 on its own page

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.

AG-033Instructions that cannot be followed from the model's seatMediumMaintainability

What it requires. A topic scope or action description a competent reader could not act on without outside knowledge: unstated abbreviations, internal process names, or an instruction whose success condition is not stated.

Why it matters. The provider's own standard is better than any threshold we would invent: put yourself in the model's shoes, and ask whether it is obvious how to use this tool from the description and parameters alone. This is irreducibly semantic and is reported as a judgement rather than a measurement. A related shape is worth naming: a sequencing constraint stated only as an instruction - "call X before Y" - is a hope, not a control.

How to fix it. Rewrite the instruction so its success condition is stated and its terms are defined in it. Where the constraint must hold, enforce it in the action rather than asking for it.

Source. Anthropic tool-description guidance

AG-033 on its own page

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.

Salesforce Flow

37 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.

AG-017A model call inside a loopHighCost & Efficiency

What it requires. A prompt template or agent action invoked inside a loop, once per record, where the platform offers a bulk or batched path.

Why it matters. Metered per action, the naive shape is expensive in a way that does not show up until the bill. At 20 Flex Credits an action, a per-record call across a 5,000-row job is a $500 line item where a batched design costs a fraction of it. Measured on the same shape, 109 evaluations through one batch took about 11.6 minutes rather than 36 times the duration of a single call, which is why batching is the remedy rather than an optimisation.

How to fix it. Move the call outside the loop and pass the collection, or use the platform's batched path.

Source. Salesforce Flex Credits pricing; our batch runner implementation

AG-017 on its own page

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-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

FL-001 on its own page

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

FL-002 on its own page

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

FL-003 on its own page

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

FL-004 on its own page

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)

FL-005 on its own page

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)

FL-006 on its own page

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

FL-007 on its own page

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

FL-008 on its own page

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

FL-009 on its own page

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

FL-010 on its own page

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

FL-011 on its own page

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

FL-012 on its own page

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

FL-013 on its own page

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)

FL-014 on its own page

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

FL-015 on its own page

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

FL-016 on its own page

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

FL-017 on its own page

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.

FL-018 on its own page

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.

FL-019 on its own page

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

FL-020 on its own page

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

FL-021 on its own page

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

FL-022 on its own page

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

FL-023 on its own page

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

FL-024 on its own page

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).

FL-025 on its own page

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

FL-026 on its own page

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)

FL-027 on its own page

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)

FL-028 on its own page

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)

FL-029 on its own page

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.

FL-030 on its own page

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

FL-031 on its own page

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

FL-032 on its own page

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

FL-033 on its own page

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

FL-034 on its own page

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

FL-035 on its own page

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

FL-036 on its own page

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.

FL-037 on its own page

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)

RC-001 on its own page

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)

RC-002 on its own page

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)

RC-003 on its own page

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)

RC-004 on its own page

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)

RC-005 on its own page

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

RC-006 on its own page

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)

RC-007 on its own page

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

RC-008 on its own page

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

RC-009 on its own page

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

RC-010 on its own page

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

RC-011 on its own page

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

RC-012 on its own page

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

RC-013 on its own page

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)

RC-014 on its own page

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)

RC-015 on its own page

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)

RC-016 on its own page

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)

RC-017 on its own page

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)

RC-018 on its own page

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

RC-019 on its own page

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)

RC-020 on its own page

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)

RC-021 on its own page

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.