Admin sharing troubleshooting
Overview
This skill is the admin persona's companion to v1.1's headline tool,
sfi.why_cant_user_see_record. The admin's first-line question is
almost always a variant of "why can't user X see record Y?" — and the
honest answer is a cascade of independent sharing rules (OWD,
permission grants, role hierarchy, owner-based sharing rules,
criteria-based sharing rules, then manual/sets/teams), where each
rule either grants visibility, denies it, or — and this is what makes
v1.1 different from a fabricated chatbot answer — admits it cannot
tell from metadata alone. This skill teaches Claude how to drive the
tool, present the cascade clearly, and turn unknown verdicts into
manual-check recommendations rather than false denials.
The cascade consumes four v1.1 edge types: grantedBy (permission
sets and profiles → objects/fields), inheritsFrom (a Role inherits
visibility from its parent Role), sharedWith (a SharingRule grants
access to a Role, Group, or Queue), and parentOf (CustomObject →
SharingRule, so the tool can find every rule targeting an object).
v1.1 records sharedWith and inheritsFrom as declared — read
straight from <sharedTo> and <parentRole> — so the cascade's
non-unknown verdicts trace to Salesforce metadata, not heuristics.
The boundary that matters for admins: v1.1 surfaces record-shape
visibility, not record-row visibility. Questions about a specific
record ID (001xx...) get translated to the underlying object shape;
record-level criteria and manual shares return unknown.
When to fire
Fire this skill on visibility-troubleshooting phrasing. Concrete triggers:
- "Why can't user X see Y?" — "Why can't Janet see Accounts?",
"Why can't
m.chen@example.comseePayment__c?", "Why can't the Sales_Rep see this object?". - "Who can see this record?" — "Who can see Accounts?", "Who has
access to
Opportunity?", "Who can readContactrecords?". - "What would let this user see Y?" — "What would give Janet access to Accounts?", "How do I let the Sales_Rep role see Opportunities?".
- "The user says they can't see Z." — natural phrasing of a support ticket. "A user reports they can't see Cases.", "User complaint: can't see the Lead queue.".
- "Visibility check for X on Y." — "Run a visibility check for Janet on Account.", "Visibility audit: Sales_Rep + Opportunity.".
- "Sharing rules touching Z." — "Show me the sharing rules on
Account.", "What sharing rules target
Payment__c?", "List the criteria-based shares on Opportunity.". - "Role hierarchy from Foo up." — "Walk the role hierarchy from Sales_Rep up.", "Show me Janet's role chain.", "What roles sit above the Sales_Manager?".
- "What grants Edit access to Y for the Foo role?" — "What gives Sales_VP Edit access to Opportunity?", "Which sharing rule lets the Sales_Manager edit Accounts?".
When NOT to fire
Defer to another skill when:
- The user asks "what breaks if I change X?" That's cross-component
impact analysis, not sharing. Defer to
architect-impact-analysis→sfi.get_impact. - The user asks "what fields does X have?" That's a schema
lookup. Defer to
answering-org-questions→sfi.list_componentsorsfi.get_component. - The user asks "where is this field used in Apex?" That's a
code-side reference question. Defer to
developer-apex-refactor→sfi.find_code_usages. - The user wants to refresh, init, or check vault status. Fire
refreshing-the-org-vault,/sfi-init, orpre-flight-checks. - The user asks a record-level question ("how many records does
this user own?", "show me Janet's open opportunities", "which
Accounts is the user the owner of?"). v1.1 has no record-level
data. Tell the admin to query their org directly with
sf data query. Do not fire the cascade against a record-id input as if it were the object shape — translate the question, but disclose the shift. - The user asks a generic "how does Salesforce sharing work?" question with no reference to their org. Answer briefly from general knowledge and offer to walk a specific cascade on a real user + object pair.
Steps
Walk these in order. Each step has a definite output that feeds the next.
Step 1 — Parse the question into a component + user context
The tool needs two inputs, and the user almost never types either of them in canonical form:
The input schema is FLAT at the top level. There is no userId and no
recordId — those keys do not exist. A call carrying only those two is
invalid-query twice over: they are stripped, and the tool then fails
its required-axis checks (provide componentId or objectApiName, and
userContext must supply at least one of: profileId, profileApiName, permissionSetIds, roleId, groupIds).
componentId(or theobjectApiNamealias) — the target object.componentIdis the canonical id (CustomObject:Account,CustomObject:Payment__c);objectApiNameis the bare api name (Account,Payment__c). Pass EITHER — supplying both that disagree isinvalid-query. Translate "Accounts" →CustomObject:Account, "the Payment object" →CustomObject:Payment__c. If the user supplies a record-row ID like001xx0000012345, translate to the object shape and disclose the shift explicitly ("I'm running the visibility cascade againstCustomObject:Account— v1.1 doesn't model record-row visibility. Continue?"). At least one of the two is REQUIRED.userContext— a NESTED object describing the user's bundle. There is no user identity parameter: v1.1 doesn't extractUserrecords, so the cascade runs against the bundle, never against a named user. It must carry at least one ofprofileId(Profile:{Name}) /profileApiName(bare name, coerced toProfile:{name}) /permissionSetIds[]/roleId/groupIds[]; an emptyuserContextisinvalid-query.accessLevel— optional, one ofread(default) /edit/delete/create. Read-only access must never be reported as edit-capable, so pass the level the admin actually asked about.
The response echoes appliedScope: { object, profile } — the
object id and profile id the cascade ACTUALLY resolved. Check it before
reporting; it is how you know an alias you passed was honored rather
than reinterpreted.
The cascade depends on the user's bundle — their profile, permission sets, role, and group memberships. If the user's question doesn't supply at least one of these — or doesn't name a user at all — ASK, before firing the tool. The honest cascade can't run without context. Good clarifying questions:
- "What's the user's role? (e.g.,
Sales_Rep,Sales_Manager)." - "Which profile is the user assigned to?"
- "Are they in any permission sets? Which ones?"
- "Are they a member of any public groups or queues?"
If the user phrasing names a role rather than a specific user
("Why can't the Sales_Rep role see Accounts?"), that's enough — the
cascade can run against the role bundle. Note the shift in your
response: "Running this against Role:Sales_Rep rather than a
specific user."
If you need to disambiguate a component name, fall back to
sfi.list_components (filter by type: 'CustomObject' or
type: 'Role') or sfi.get_component for the canonical ID.
Step 2 — Call sfi.run_analysis with { "name": "sfi.why_cant_user_see_record", "args": { … } }
Default invocation:
{
"componentId": "CustomObject:Account",
"accessLevel": "read",
"userContext": { "profileApiName": "Sales_Rep", "roleId": "Role:Sales_Rep" }
}
The response shape (per the v1.1 contract). Each reasoning[] entry has
exactly four keys — stage, verdict, reason, and an optional
traversed[] (plus an optional mutedBy[] when a muting permission set
in a PermissionSetGroup flipped an object-CRUD precondition off). There
is no rule, no decision, no name, no ruleType, and no note:
{
"data": {
"verdict": "visible" | "restricted" | "unknown",
"appliedScope": { "object": "CustomObject:Account", "profile": "Profile:Sales_Rep" },
"reasoning": [
{ "stage": "OWD", "verdict": "restricted", "reason": "..." },
{ "stage": "PermissionGrant", "verdict": "visible", "reason": "..." },
{ "stage": "RoleHierarchy", "verdict": "restricted", "reason": "...", "traversed": ["Role:..."] },
{ "stage": "OwnerSharingRule", "verdict": "restricted", "reason": "..." },
{ "stage": "CriteriaSharingRule", "verdict": "unknown", "reason": "..." },
{ "stage": "ManualSharing", "verdict": "unknown", "reason": "..." }
]
}
}
stage is one of exactly these fourteen: OWD, PermissionGrant,
SystemPermission, RecordType, RoleHierarchy, OwnerSharingRule,
CriteriaSharingRule, RestrictionRule, ScopingRule,
PermissionSetGroup, TerritoryAndGuestRules, ManualSharing,
SharingSets, AccountTeams. verdict is one of exactly three:
visible, restricted, unknown. Do not invent a stage or a verdict
outside these sets, and do not report a stage the response did not
contain.
OWD values. The OWD stage reads properties.sharingModel off the
CustomObject. The extractor accepts exactly these values: Private,
Read, ReadSelect, ReadWrite, ReadWriteTransfer,
ControlledByParent, ControlledByCampaign, FullAccess. There is
no Public OWD value — Salesforce's UI labels are "Public Read
Only" / "Public Read/Write", but the metadata values are Read and
ReadWrite. Quote the metadata value, and gloss the UI label in prose
if it helps the admin find the setting.
Sharing-rule types. The extractor's ruleType values are owner,
criteria, guest, territory, and territoryGroup — not
owner-based / criteria-based. Those hyphenated forms are fine as
ENGLISH ("the owner-based sharing rules"); they are not field values.
Note also that the cascade surfaces owner rules and criteria rules as
two distinct STAGES (OwnerSharingRule / CriteriaSharingRule), so
you rarely need to quote ruleType at all.
The cascade runs top-to-bottom. The first step that resolves to
visible terminates execution and the top-level verdict becomes
visible. If every step is either restricted or unknown, the
top-level verdict is restricted when OWD is Private/
ControlledByParent with no overriding step, and unknown whenever
an unresolvable step (manual sharing, unmodeled criteria predicate)
sits between the user and the record.
Step 3 — Present the cascade as a timeline
The raw reasoning[] array is the right shape for human reading: a
bulleted timeline of stages, each with its rule, verdict, and reason.
Walk the array in order and surface every step — including the ones
that returned unknown. Do not silently drop unknown steps.
They're load-bearing for admin trust; the omission would make the
report look complete when it isn't.
For each step:
- State the stage name (
OWD,RoleHierarchy,SharingRule,ManualSharing,SharingSet,AccountTeam). - State the verdict (
visible,restricted, orunknown). - State the reason (cite the
note, plus any cited canonical IDs likeSharingRule:Account.Share_Tech_Accounts_With_SalesorRole:Sales_VP). - If the verdict is
unknown, recommend the manual check explicitly — name what the admin would inspect in the Salesforce UI (the record's Share button for manual sharing; Setup → Sharing Sets for sharing sets; Setup → Account Teams for teams; the actual record's field values for criteria predicates).
One correction to make when you quote the SharingSets stage: its
reason still says sharing sets are "not modeled in v1.1", and that
sentence is out of date. SharingSet IS an extracted component type —
sfi.list_components({ type: 'SharingSet' }) and sfi.get_component
answer on one, and each node carries its accessMappings
(userField → objectField per mapped object) and granted
profiles. Two things are still true and are why the verdict stays
unknown: a vault built before the extractor shipped holds no
SharingSet nodes until a re-refresh (object_360 says so per vault:
"NOT MODELED in this vault … NOTHING was checked"), and whether a set
grants a SPECIFIC user access to a SPECIFIC record needs that record's
objectField value and that user's userField value — live record
data. Say "the configuration is readable; the applicability is not"
rather than "sf-intelligence cannot see sharing sets".
Step 4 — Provide the bottom-line aggregate verdict
After the timeline, give the top-level verdict in one sentence,
plain language. Examples:
visible: "Net result:User:m.chen@example.comcan seeCustomObject:Accountrecords, granted by step {N} ({stage name})."restricted: "Net result:User:...is blocked fromCustomObject:...records by the OWD default ofPrivate, with no overriding step in v1.1's modeled rules."unknown: "Net result: v1.1 cannot tell — the cascade reached anunknownstep at {stage} that requires record-level data or a rule type v1.1 doesn't model. Treat as inconclusive and verify manually per the steps above."
Step 5 — Suggest next steps when the verdict is restricted
If the verdict is restricted, the admin's next move is usually "how
do I grant access?" The cascade's reasoning[] already names every
modeled rule that could have granted access; surface them as fix
options:
- "Add the user to
Group:Sales_Public_Groupto grant access via the existing criteria-based ruleSharingRule:Account.Share_Tech_Accounts_With_Sales(accessLevel: Edit)." - "Place the user's role under
Role:Sales_VPin the hierarchy — that's the role with thesharedWithedge toSharingRule:Account.Share_VP_Accounts_With_Execs." - "Grant the relevant permission set; the existing v1.0
grantedByedges showPermissionSet:Sales_Manageralready grants access to this object."
Cite canonical IDs for every component you reference. The admin needs to be able to click through to the vault and verify.
When the verdict is unknown, do not suggest fixes — instead,
restate the manual-check recommendations from Step 3.
Reporting format
Use the synthetic-v1.1 fixture for the worked example. Suppose
Janet is a user in the Sales_Rep role, and the admin asks:
"Why can't Janet (Sales_Rep) see Account records?"
After clarifying that Janet's role is Sales_Rep and there are no
permission set overrides, Claude fires the tool:
{
"componentId": "CustomObject:Account",
"accessLevel": "read",
"userContext": { "profileApiName": "Sales_Rep", "roleId": "Role:Sales_Rep" }
}
The tool returns (illustrative):
{
"data": {
"verdict": "unknown",
"appliedScope": { "object": "CustomObject:Account", "profile": "Profile:Sales_Rep" },
"reasoning": [
{ "stage": "OWD", "verdict": "restricted", "reason": "Account sharingModel is Private; cascade continues." },
{ "stage": "RoleHierarchy", "verdict": "restricted", "reason": "No role in the chain holds a sharedWith grant on Account.", "traversed": ["Role:Sales_Rep","Role:Sales_Manager","Role:Sales_VP","Role:Executive_Officer"] },
{ "stage": "OwnerSharingRule", "verdict": "restricted", "reason": "SharingRule:Account.Share_VP_Accounts_With_Execs shares FROM Role:Sales_VP TO Role:Executive_Officer; the role bundle is in neither." },
{ "stage": "CriteriaSharingRule", "verdict": "unknown", "reason": "SharingRule:Account.Share_Tech_Accounts_With_Sales matches on 'Industry = Technology'; evaluating that criterion needs record-level data v1.1 does not hold." },
{ "stage": "ManualSharing", "verdict": "unknown", "reason": "v1.1 does not model manual sharing; check the record's Share button in Salesforce Setup." },
{ "stage": "SharingSets", "verdict": "unknown", "reason": "v1.1 does not model sharing sets." },
{ "stage": "AccountTeams", "verdict": "unknown", "reason": "v1.1 does not model Account teams." }
]
}
}
Claude's presentation back to the admin:
Visibility cascade for the
Sales_Repbundle (Profile:Sales_Rep+Role:Sales_Rep) onCustomObject:Account— v1.1 doesn't extractUserrecords, so this is the bundle's access, not Janet's specifically:
- OWD —
restricted. AccountsharingModelisPrivate; cascade continues.- RoleHierarchy —
restricted. WalkedRole:Sales_Rep → Role:Sales_Manager → Role:Sales_VP → Role:Executive_Officer; no role in the chain holds asharedWithgrant on Account.- OwnerSharingRule —
restricted.SharingRule:Account.Share_VP_Accounts_With_Execsshares fromRole:Sales_VPtoRole:Executive_Officer; the role bundle is in neither.- CriteriaSharingRule —
unknown.SharingRule:Account.Share_Tech_Accounts_With_Salesmatches onIndustry = Technology; evaluating that criterion needs record-level data v1.1 doesn't hold. Manual check: pull a sample Account record and verifyIndustry.- ManualSharing —
unknown. v1.1 doesn't model manual sharing. Manual check: open the record in Salesforce and inspect the Share button.- SharingSets —
unknown. v1.1 doesn't model sharing sets. Manual check: Setup → Sharing Sets.- AccountTeams —
unknown. v1.1 doesn't model Account teams. Manual check: open the Account record and inspect the Account Team related list.Net result: v1.1 cannot tell. The cascade reached
unknownsteps that require record-level data or rule types v1.1 doesn't model. Treat as inconclusive and verify manually per the steps above.If you want to grant Janet access without waiting on the manual check, the modeled options are:
- Add
User:janet@example.comtoGroup:Sales_Public_Group— the criteria rule will then grant Edit access to Accounts matchingIndustry = Technology.- Move
Role:Sales_RepunderRole:Executive_Officerin the hierarchy (intrusive; only do this if it matches your real reporting line).v1.1 sharing analysis covers: OWD, role hierarchy via
inheritsFrom, owner-based sharing rules, and criteria-based sharing rules withsharedToresolution. It does not cover manual sharing, sharing sets, Account teams, record-level ownership, or evaluation of criteria predicates against record data. v1.1 surfaces record-shape visibility, not record-row visibility.
Every step appears with its verdict. Every unknown carries a
manual-check pointer. The bottom line is one sentence. The boundary
disclosure is fixed-form and unskippable.
Boundary disclosure
v1.1's sharing cascade has well-defined gaps. Surface this list
whenever the admin is about to act on the report, and always when
any step returned unknown:
- Manual sharing. The per-record Share button. v1.1 doesn't read
the corresponding
__Sharerows from Salesforce. Reported asunknown; admin checks the record's Share button. - Sharing sets. Used by Experience Cloud / Community licensing
to share records with external users via a related Account/Contact.
Not extracted in v1.1. Reported as
unknown. - Account teams / Opportunity teams. Per-record team membership
that grants visibility. Not extracted in v1.1. Reported as
unknown. - Record-level criteria evaluation. A criteria-based sharing rule
with
criteriaItemslikeIndustry = Technologyrequires the record's actual data to evaluate — v1.1 has only metadata. Reported asunknownfor that step; admin pulls a sample record to check. - Implicit sharing. Parent-child standard relationships (e.g., Account → Contacts sharing) are not yet modeled. If you grant a user visibility to an Account, Salesforce implicitly shares the Contacts; v1.1's cascade does not infer this.
- Standard CRUD on standard objects, special object-level
permissions. Profile-level CRUD (
Read,Edit,Create,Delete) is read from the v1.0 PermissionSet / Profile extractors, but v1.1's tool does not yet special-case object-level "Modify All Data" or "View All". If the cascade returnsrestrictedand you know the user has elevated privileges (e.g., System Administrator profile, "Modify All Data" permission), check those manually before acting. - PermissionSetGroup MUTING (R7-W4). When a user is assigned a
PermissionSetGroup, the cascade SUBTRACTS the group's muting
permission set(s) from the object-CRUD precondition — a CRUD
bit (or View/Modify All Data) a group member grants but the
group's muting set denies is NOT counted. So a user whose object
Read is muted away inside the group returns
restricted, and thePermissionGrantstep plus a top-levelmutedByname the muting set. Muting is group-scoped (a grant from the profile or a permission set assigned OUTSIDE the group survives) and is NOT subtracted from the record-visibility BYPASS stages (object/system View/Modify All) — for the full muting-correct net grant usesfi.effective_permissions. A muting set present in a pre-R6-06 vault (no muted-perm data) or referenced-but-absent CANNOT be subtracted; the tool DISCLOSES this as a possible overstatement (re-run/sfi-refresh), so never read a muting-present verdict as guaranteed-tight. - User → Role mapping. v1.1 does not extract
Userrecords; the cascade's role-hierarchy step isunknownif the user's role can't be resolved from the input context. v1.7's Tooling API tier may surface a synthetic mapping viaUser.UserRoleId.
Treat unknown verdicts as a flag for manual investigation, not
as denial. Treat restricted verdicts as "v1.1's modeled rules
all say no" — still subject to the standard-CRUD caveat above.
Treat visible verdicts as "v1.1 traced a declared chain of
metadata that grants access" — high trust, but the cited rule should
still be the admin's anchor when changing access.
Anti-patterns
| Mistake | Why it's wrong |
|---|---|
Presenting an unknown step as restricted. |
unknown means "v1.1 can't tell"; it is not denial. A user the cascade reports as unknown for manual sharing may, in reality, have manual access. Surface unknown as a flag to check, never collapse it into "no." |
Firing sfi.why_cant_user_see_record without user context. |
The cascade needs the user's role, profile, perm sets, or group memberships. Without at least one of these the role-hierarchy and sharing-rule steps are uniformly unknown and the answer is useless. ASK the admin before firing if context is missing. |
| Conflating "this user" with "this profile". | User-level visibility depends on the bundle (profile + permission sets + role + groups), not any one piece. A profile that allows Read doesn't help if OWD is Private and no sharing rule reaches the user. |
| Fabricating an answer when v1.1 can't tell. | The honesty axis is constitutional. If the cascade returns unknown, do not paper over it with general Salesforce knowledge from training data. Refuse honestly and recommend the manual check. |
Treating a record-row ID (001xx0000012345) as the cascade input. |
v1.1 surfaces record-shape visibility, not record-row. Translate to the object shape, disclose the shift, and run the cascade — or, if the question is genuinely record-row ("can Janet see this specific Account?"), refuse and direct the admin to a live SOQL query against the org. |
Silently dropping unknown steps from the timeline because they look noisy. |
Every step is load-bearing. Dropping unknown steps makes the report look complete when it isn't — and is the most expensive shortcut in this skill, because the admin makes a sharing decision and skips the manual check. |
Skipping the boundary disclosure when the verdict is visible. |
The disclosure is the admin's protection against the wrong mental model. A visible verdict still has to coexist with un-modeled grants the admin might be relying on. Always disclose. |
Inverting "who can see this record" by writing a SOQL query against UserRecordAccess. |
v1.1 is offline-only; live queries are out of scope for the cascade. Use sfi.list_components to enumerate SharingRule nodes with parentOf from the target object, then walk sharedWith edges to surface the grantees; surface the role-hierarchy roots that reach into those grantees via inheritsFrom. |
Citing parsed or heuristic confidence on sharedWith or inheritsFrom. |
Both edges are declared in v1.1 — read directly from <sharedTo> and <parentRole> XML. Don't introduce uncertainty where the metadata is plain. |
Example interaction
User: "Why can't Janet (Sales_Rep) see Account records?"
Claude's flow:
- Parse. Component =
CustomObject:Account. User context = roleRole:Sales_Rep. No profile or perm-set context provided. Ask: "Does Janet have any sharing-relevant permission sets, or is she on the base profile? Is she a member ofGroup:Sales_Public_Groupor any other public groups?" — but only if those would change the answer. For a v1.1 cascade against Account, the role and group memberships are the load-bearing inputs; the profile-level Read is overridden by OWD onPrivatestandard objects. - Confirm Janet's bundle (assume the admin says: "Role
Sales_Rep, no extra perm sets, not in any public group"). - Fire
sfi.run_analysiswith{ "name": "sfi.why_cant_user_see_record", "args": { … } }with{ componentId: 'CustomObject:Account', accessLevel: 'read', userContext: { profileApiName: 'Sales_Rep', roleId: 'Role:Sales_Rep' } }. - Present the cascade timeline (see Reporting format above):
OWD
restricted, role hierarchyrestricted, the two existing sharing rules on Account returnunknown(criteria) andrestricted(owner), and manual / sets / teams returnunknown. - Net result. v1.1 cannot conclude. Top-level verdict
unknown. - Fix options (since
restrictedis part of the picture): "Add Janet toGroup:Sales_Public_Group— this would let the existing criteria rule grant Edit access on Accounts whereIndustry = Technology. Verify against a sample Account first." - Boundary disclosure — verbatim fixed-form paragraph (see Boundary disclosure section).
If the admin follows up with "Janet's role is actually Sales_VP,
not Sales_Rep — sorry", re-fire the tool with the corrected user
context. The cascade's RoleHierarchy step will now traverse Role: Sales_VP → Role:Executive_Officer, and the owner rule
SharingRule:Account.Share_VP_Accounts_With_Execs (which has
sharedFrom = Role:Sales_VP, sharedTo = Role:Executive_Officer)
will resolve visible for any Account owned by a Sales_VP — though
the criteria rule is still unknown for the record-level
question.
Verification
Before sending a response, confirm:
- I translated the user's reference into a canonical
componentId(CustomObject:{ApiName}) orobjectApiName(bare api name) plus auserContextcarrying at least one ofprofileId/profileApiName/permissionSetIds[]/roleId/groupIds[], asking for the user's role / profile / perm sets / groups when the question omitted them. I did NOT passuserIdorrecordId— those keys do not exist on this tool. - I checked
appliedScopeon the response and reported the object + profile the cascade ACTUALLY resolved, not the ones I assumed. - If the user supplied a record-row ID (
001xx...), I translated to the object shape and disclosed the shift before firing. - I called
sfi.run_analysisforsfi.why_cant_user_see_recordexactly once per bundle. (If the admin corrected context, I refired.) - I named each step by its real
stagevalue (one of the fourteen) and its realverdict(visible/restricted/unknown), quotingreason— never an inventedrule/decision/notekey. - I quoted OWD as a real
sharingModelmetadata value (Private/Read/ReadSelect/ReadWrite/ReadWriteTransfer/ControlledByParent/ControlledByCampaign/FullAccess) — neverPublic, which is a UI label, not a metadata value. - I presented every step in
reasoning[]— includingunknownsteps — as a bulleted timeline with stage, verdict, and reason. - Every
unknownstep carried a manual-check recommendation naming the specific Salesforce UI surface to inspect. - I cited canonical IDs (
Role:...,Group:...,SharingRule:...,Queue:...,CustomObject:...) for every component named. - I gave the bottom-line verdict in one sentence.
- If the verdict was
restricted, I suggested fix options grounded in the cascade's modeled rules. - I appended the v1.1 boundary disclosure — manual sharing, sharing sets, Account teams, record-level criteria, implicit sharing, and the standard-CRUD caveat.
- I did not present
unknownasrestricted, and I did not fabricate an answer when the cascade said it couldn't tell.
Grounding & routing (shared contract). For a vague or broad ask, call sfi.route_question first — in the default hybrid mode it returns a meaning-ranked toolCandidates shortlist (which YOU pick from) plus a suggested plane and a route hint (and whether to sfi.resolve a name first). Default tool profile is core: only the core spine (including sfi.live_consent) is directly invokable. For every other sfi.* analysis, call sfi.run_analysis with { "name": "sfi.<tool>", "args": { … } } (or follow route_question.invoke, which already wraps non-core steps). Optional: sfi.describe_analysis first when args are unclear. Every org fact must come from an sfi.* tool call, cited by its canonical id — never from memory. Build the answer only from what the tools returned, then pass it through sfi.synthesize_answer, which flags any hallucinatedIds (canonical ids no tool produced). Full cascade: using-sf-intelligence.