Salesforce sharing & visibility troubleshooting

Support tickets like "why can't this user see this record?" need more than generic advice. sf-intelligence traces the visibility cascade - Profiles, Permission Sets, OWD, sharing rules, restriction rules - from metadata retrieved from your org.

Last updated 2026-07-29

Short answer: Ask sf-intelligence "why can't a Support Agent see this Widget record?" and it walks the sharing cascade stage by stage - org-wide default, then object and field grants, then system permissions, then the role hierarchy, then owner and criteria sharing rules, then restriction and scoping rules - and names the stage that decided the outcome. Any stage your retrieved metadata can't settle comes back unknown instead of a guess.

trace a real visibility cascade in 2 minutes - no org, no auth

terminal
claude mcp add --transport stdio --scope user sf-intelligence-demo -- npx -y sf-intelligence demo

Then ask "why can't a Verdant_Installer see an Invoice?", "who can access the Payment__c object?", and "what can the Verdant_Read_Only profile actually do?". The demo serves a synthetic "Verdant Energy" org with real profiles, permission sets, roles, groups, queues and sharing rules wired up, fully offline - no Salesforce login, no sf CLI. more on the demo →

What questions does this answer?

Sharing tickets arrive as one-line complaints and turn into an afternoon of clicking. These are the shapes sf-intelligence takes directly:

  • "Why can't User X see this Widget record?"
  • "Who can edit the Status field on Widget__c?"
  • "Who can access the Case object at all?"
  • "What permission sets grant delete on Opportunity?"
  • "Does this Profile have View All Data?"
  • "What would change if I assigned this permission set to that user?"

Why can't this user see this record?

Salesforce visibility is not one setting, it is a cascade, and the reason a ticket is slow to close is that the answer can live at any layer of it. why_cant_user_see_record walks the layers in the order Salesforce itself applies them and reports which one produced the outcome:

  1. Org-wide default - the object's sharingModel. A Private object starts from "owner and hierarchy only"; a Public Read/Write object starts from "everyone with object access."
  2. Object and field grants - the Profile plus every assigned Permission Set, unioned with max-wins, so a grant anywhere in the stack is a grant.
  3. System permissions - View All Data, Modify All Data, and the per-object View All / Modify All, which short-circuit everything below them.
  4. Role hierarchy - whether the user sits above the record owner's role, which is the quiet reason a manager can see something their peer cannot.
  5. Owner-based sharing rules - shares driven by who owns the record, typically to a role, group, or queue.
  6. Criteria-based sharing rules - shares driven by field values on the record itself.
  7. Restriction and scoping rules - the layers that can take visibility away again after everything above granted it.

Each stage is reported with what it found in your retrieved metadata, and each carries a verdict of granted, blocked, or unknown. That third value is the important one. A stage that needs record-level data or runtime membership to settle is marked unknown and handed back to you to verify, rather than being quietly resolved in whichever direction would make the answer look complete.

What does the answer actually look like?

Take the everyday version of the ticket. A support agent says they cannot open a Widget record that a colleague sent them, and Widget__c has an org-wide default of Private.

claude - sf-intelligence
 why can't the Support Agent profile see Widget records?
▸ CustomObject:Widget__c — OWD Private
  1 org-wide default ............ blocked   Private: owner + hierarchy only
  2 object grants ............... granted   Profile:Support_Agent → Read
  3 system permissions .......... blocked   no View All Data, no View All on Widget__c
  4 role hierarchy .............. blocked   Role:Support_Agent not above Role:Sales_Rep (owner)
  5 owner sharing rules ......... blocked   1 rule found, shares to Group:Ops_Group only
  6 criteria sharing rules ...... granted*  rule on Status__c = "Escalated" — depends on this record's value
  7 restriction rules ........... unknown   RestrictionRule not retrieved this refresh
▸ verdict: object access yes, record access unproven
  deciding stage: criteria sharing rule needs the record's Status__c value
  provenance offline_snapshot · completeness: partial

Read what that actually tells you. The profile is not the problem - object-level Read is granted. The reason the agent is stuck is that Widget__c is Private, they are not above the owner in the role hierarchy, and the only sharing rule that could reach them is criteria-based on a field value the vault cannot evaluate for one specific record. That is a two-minute answer to a question that normally means opening the object's sharing settings, the profile, every permission set the user holds, the role hierarchy, and the sharing rules list in separate tabs.

Note the asterisk and the unknown. The criteria rule is reported as a conditional grant, not a grant, because whether it fires depends on record data. The restriction-rule stage is unknown because that metadata family was not in the last retrieve, and "not retrieved" is reported as not checked rather than as none in the org.

Who can see this - and who can edit this field?

The same permission model answers the question from the other end, which is usually the audit version rather than the ticket version. who_can_access_object enumerates every Profile, Permission Set, role, and group that statically grants access to an object, so you can see the full reachable population instead of checking one user at a time. field_access_audit does the field-level equivalent: give it a field and it cross-walks every container that grants read or edit on it through the grantedBy edges, which is the fastest way to answer "who can edit this sensitive field" without trusting an org chart. effective_permissions flips to a single user and computes the union of their profile and assigned permission sets with each permission attributed back to the container that granted it - so when something is over-granted you know which container to fix.

Two more are worth knowing about because they answer questions people rarely think to ask. user_ability covers what a profile or permission set can run or do beyond record CRUD, which is where app, tab, and system-level capability questions live. layout_for_user walks the layout-routing cascade - profile lookup, then layout assignment, then record-type resolution - for the "this user sees the wrong page layout" ticket, which looks like a sharing problem and is not one.

Why doesn't a general AI model get this right?

A general model knows how Salesforce sharing works in theory, and will happily produce a plausible-sounding cascade walkthrough with invented profile names. sf-intelligence knows which Profiles and Permission Sets exist in your org, which fields they expose, which sharing rules were actually written, and whether a restriction rule was retrieved at all. Every answer carries provenance (offline_snapshot by default) and a completeness marker, and when it cannot determine an outcome it returns unknown rather than guessing visible. A confident wrong answer about who can see a record is worse than no answer, because it ends the investigation.

What needs the opt-in live plane?

The vault answers the structure of access offline, from metadata. Some sharing questions are not structural - they are about runtime rows that never appear in metadata XML at all, and those need the read-only live plane turned on explicitly.

QuestionAnswered byNeeds live?
Which containers grant access to this object or field?who_can_access_object, field_access_auditNo - offline vault
Why is this profile blocked on this object?why_cant_user_see_recordNo - offline vault
What does this profile plus its permission sets add up to?effective_permissionsNo - offline vault
Who actually holds this permission set or profile, by name?live_permset_holdersYes - assignments are runtime rows
Who is actually in this queue or public group?live_group_membersYes - XML carries declared members only
What does this one user hold right now?live_user_permsetsYes
Can this user read this specific record, right now?live_record_accessYes - the org's own sharing calculation
Who is this one record explicitly shared with, and why?live_record_sharesYes - reads the object's Share table

The live plane is off by default, consent-gated, budget-capped, and read-only - a curated roster of SOQL reads, not arbitrary query access. It exists precisely so the offline answer never has to bluff about assignment data it cannot see. When a vault tool hits one of these boundaries it names the live tool that would close the gap instead of estimating.

What can it still not tell you?

  • Record-level outcomes, offline - it analyses permission containers and rule definitions, not "does User X own this particular record." A criteria sharing rule's outcome depends on that record's field values, so the offline answer is conditional by construction.
  • Manual shares, sharing sets, and team membership - these are runtime rows, not metadata. Offline they are unknown; live_record_shares reads them from the Share table when the live plane is enabled.
  • Anything added since your last refresh - the vault is a point-in-time snapshot. A permission set created this morning is not in last week's answer, which is why health_check reports vault age and flags staleness.
  • Families the retrieve skipped - if restriction or scoping rule metadata was not pulled, the answer carries an explicit blind spot for that stage. Run coverage_report to see what the last refresh actually retrieved before you rely on an absence.
  • No write path - it will tell you which container to change and never change it. Granting the access stays a deliberate human action in Setup or a deploy.

For the full boundary list and how each of these is tested, see the trust page. To trace what a permission-set change would touch elsewhere before you make it, see Salesforce impact analysis.

Stop guessing about access.

Read-only, offline, free. Ask permission questions in plain language from any MCP client.