Resolve open decisions: per-user auth pattern + reasoning model

Fold Adam's decisions and deep-research (wf_1bf9e142) outcomes into the plan:
- D4: ES/Apex actions + Per-User OAuth Browser Flow External Credential -> Cognito;
  native remote-MCP connector off the per-user hop (Beta, per-user binding unconfirmed).
- D5: AWS-Hosted Claude as the planner; BYOLLM ruled out (custom-action-only, routes
  through SF Models API/Trust Layer). Guardrail moves to the MCP/action layer (revises D11).
- D1 accepted; D3 accepted; G8 corpus authoring deferred (fund when needed).
- Resolve gaps G1/G2/G6; add §0.1 resolutions and a Phase-0 verify-in-org gate.
This commit is contained in:
Adam Moussa 2026-06-11 11:58:11 -04:00
parent e7e96458b3
commit eaf2aae480

View file

@ -28,7 +28,9 @@ single hardest reconciliation is **per-user identity**: Agentforce's native remo
2026) and authenticates connectors through **Named/External Credentials**, whose **Per User** OAuth identity type 2026) and authenticates connectors through **Named/External Credentials**, whose **Per User** OAuth identity type
exists at the platform level but is **not yet confirmed for the MCP connector** — if a connector can only bind a exists at the platform level but is **not yet confirmed for the MCP connector** — if a connector can only bind a
**Named Principal** (one service identity), our per-user JWT, ABAC Gmail isolation, and trifecta guarantees break. **Named Principal** (one service identity), our per-user JWT, ABAC Gmail isolation, and trifecta guarantees break.
That is the controlling risk of this migration (Gap G1, §5) and it drives the surface-integration recommendation. That was the controlling risk of this migration (Gap G1, §5). **RESOLVED 2026-06-11 (§0.1):** we take the GA
External Service/Apex action path with a Per-User OAuth Browser Flow credential and keep the native MCP connector
off the per-user hop, so the risk is mitigated rather than load-bearing.
**Decision log (committed picks — 1 line + rationale + citation):** **Decision log (committed picks — 1 line + rationale + citation):**
@ -37,8 +39,8 @@ That is the controlling risk of this migration (Gap G1, §5) and it drives the s
| D1 | **3 agents**: Seahaven Ops, Seahaven Finance, Lauren Exec | 1:1 with trust tiers + Google groups; UX-layer trifecta separation | design.md §12, §3 | | D1 | **3 agents**: Seahaven Ops, Seahaven Finance, Lauren Exec | 1:1 with trust tiers + Google groups; UX-layer trifecta separation | design.md §12, §3 |
| D2 | Deploy as **Agentforce Employee Agents in Slack** | Slack is our surface; only Employee Agents deploy to Slack | `FACT` slack.com/help 36218109305875 | | D2 | Deploy as **Agentforce Employee Agents in Slack** | Slack is our surface; only Employee Agents deploy to Slack | `FACT` slack.com/help 36218109305875 |
| D3 | **Refine design.md §12**: remove `finance:read` from Lauren Exec; finance lookups go through the Finance agent | Gmail-read + finance-read + a write/egress tool in one session is the exfiltration trifecta | design.md §2.5, §3 (trifecta); §5 | | D3 | **Refine design.md §12**: remove `finance:read` from Lauren Exec; finance lookups go through the Finance agent | Gmail-read + finance-read + a write/egress tool in one session is the exfiltration trifecta | design.md §2.5, §3 (trifecta); §5 |
| D4 | Reach MCP servers via a **Per-User External Credential (OAuth 2.1 Browser Flow → Cognito)**, wrapped as **Apex/External Service actions** until native per-user MCP auth is GA | Preserves real-user `sub` in the JWT; native MCP connector per-user binding unconfirmed in Beta | `FACT` Named Credentials OAuth dev guide; Gap G1/G2 §5 | | D4 | **RESOLVED (2026-06-11, §0.1):** reach MCP tools via **GA External Service (OpenAPI) actions** (or Apex `@InvocableMethod`) authenticated by a **Per-User OAuth 2.1 Browser Flow External Credential → Cognito**. Native remote-MCP connector is NOT used for the per-user hop. | Per-user OAuth is GA; native custom-MCP per-user binding is unconfirmed and documented per-user identity exists only for SF-**hosted** MCP. Trade-off: lose the MCP transport on the Agentforce→tool hop (tools re-exposed as OpenAPI/Apex). | `FACT` research wf_1bf9e142; Named Credentials OAuth dev guide; G1/G2 §5 |
| D5 | Agent reasoning model = **Anthropic Claude on Amazon Bedrock**, via **BYOLLM** if it can serve as the Atlas planner, else the **AWS-Hosted Claude Sonnet 4** option | Retains our Claude lineage (legacy Sonnet 4.5/4.6) + Trust Layer; BYOLLM = 30% fewer Einstein Requests | `FACT` developer.salesforce.com supported-models; Agentforce 360 for AWS; Gap G6 §5 | | D5 | **RESOLVED (2026-06-11, §0.1):** agent reasoning/planner model = **AWS-Hosted Claude (Salesforce-managed, on Bedrock)**. **BYOLLM is NOT used for the planner.** | BYOLLM is documented only for custom actions, never as a planner option, and routes back through Salesforce's Models API/Trust Layer anyway. AWS-Hosted is the only documented way to keep Claude as planner. | `FACT` research wf_1bf9e142; developer.salesforce.com supported-models |
| D6 | KB → **Agentforce Data Library (unstructured) on Data Cloud**, replacing Bedrock KB `LSDCNHTH6O` + AOSS | Data Libraries auto-create a Data Cloud search index + retriever; managed RAG | `FACT` Trailhead/Atrium Data Libraries; design.md §3 | | D6 | KB → **Agentforce Data Library (unstructured) on Data Cloud**, replacing Bedrock KB `LSDCNHTH6O` + AOSS | Data Libraries auto-create a Data Cloud search index + retriever; managed RAG | `FACT` Trailhead/Atrium Data Libraries; design.md §3 |
| D7 | **Retire** `po-sync` / `workorder-sync` KB feeds; structured WO/PO/payments stay **live MCP lookup tools** | Data Libraries are unstructured-only; structured data belongs in DDB-backed MCP tools | `FACT` Data Libraries unstructured-only; design.md §3 | | D7 | **Retire** `po-sync` / `workorder-sync` KB feeds; structured WO/PO/payments stay **live MCP lookup tools** | Data Libraries are unstructured-only; structured data belongs in DDB-backed MCP tools | `FACT` Data Libraries unstructured-only; design.md §3 |
| D8 | Proactive jobs (`fetch-classify`, `daily-digest`, `reminder`, `notion-sync`) **stay as our scheduled Lambdas**, not Agentforce; HIGH-priority alerts continue as **Slack DMs** | No conversational equivalent; keeps Haiku classifier in our Bedrock account; cheapest reliable path | design.md §5; §1f below | | D8 | Proactive jobs (`fetch-classify`, `daily-digest`, `reminder`, `notion-sync`) **stay as our scheduled Lambdas**, not Agentforce; HIGH-priority alerts continue as **Slack DMs** | No conversational equivalent; keeps Haiku classifier in our Bedrock account; cheapest reliable path | design.md §5; §1f below |
@ -58,6 +60,40 @@ medium**, **3 low**.
--- ---
## 0.1 Decision resolutions — 2026-06-11 (Adam + deep-research wf_1bf9e142)
All five §6 open decisions are now resolved. Research = a 6-angle, 23-source, 25-claim adversarially-verified
deep-research pass (25/25 confirmed); primary Salesforce/AWS/Anthropic sourcing. Findings supersede the
provisional D4/D5 wording above and the open items in §6.
| §6 item | Resolution | Basis |
|---------|-----------|-------|
| 1. Surface + licensing | **ACCEPTED** — Agentforce Employee Agents in Slack; Agentforce + Data Cloud licensing accepted. | Adam, 2026-06-11 |
| 2. Reasoning model | **AWS-Hosted Claude (SF-managed)** as the planner. BYOLLM ruled out for the planner (only Salesforce Default / AWS-Hosted drive the Atlas reasoning engine; BYOLLM is custom-action-only and still routes through SF's Models API/Trust Layer). | research wf_1bf9e142 (Q2) |
| 3. Strip finance from Lauren (D3) | **ACCEPTED.** | Adam, 2026-06-11 |
| 4. Per-user auth path (D4) | **External Service (OpenAPI) / Apex actions + Per-User OAuth Browser Flow External Credential → Cognito.** Native remote-MCP connector is Beta and its per-user binding is unconfirmed — do NOT depend on it for the per-user hop. | research wf_1bf9e142 (Q1) |
| 5. Fund SA8000/handbook corpus (G8) | **DEFERRED — fund when needed** (not now). SA8000/compliance + HR agents stay blocked until content is authored; the agents must decline rather than hallucinate in the interim. | Adam, 2026-06-11 |
**Two consequences that ripple into the design (must be honored downstream):**
1. **The Agentforce→tool hop is NOT MCP.** Because per-user identity is only achievable on the GA External
Service/Apex action path (not the Beta MCP connector), Agentforce reaches our tools through an **OpenAPI/Apex
facade in front of each MCP server**, authenticated per-user to Cognito. The `sh-mcp-ops`/`-finance` servers,
their JWT validation, scopes, audience-binding, and PII redaction are **unchanged** — only the Agentforce-side
transport changes from MCP to OpenAPI/Apex actions. (Other MCP clients can still speak MCP to the same servers.)
Browser Flow requires an interactive first-auth per user (fine for Slack users; the proactive Lambdas in §1f
are unaffected — they use offline creds).
2. **Our Bedrock guardrail cannot sit on the planner path.** Both AWS-Hosted and BYOLLM keep Salesforce in the
inference path, so keeping inference + our own guardrail in account `328440206208` is **unsatisfiable on the
planner path today**. The Einstein **Trust Layer** covers planner-path moderation; **our guardrail + PII
redaction move entirely to the MCP/action layer** (already the plan for PII — design.md §2.5). This **revises
D11**: the guardrail is applied at the MCP/action layer, not "on the BYOLLM model path."
**Dropped claim:** the "BYOLLM = ~30% fewer Einstein Requests" figure was **not corroborated** by any verified
source — removed from cost modeling.
---
## 1. Platform-level design ## 1. Platform-level design
### 1a. Agent roster — how many, and why ### 1a. Agent roster — how many, and why
@ -434,12 +470,12 @@ Severity: **C**ritical / **M**edium / **L**ow. "Verify" = check against current
| # | Gap | Sev | Impact | Workaround / status | Verify | | # | Gap | Sev | Impact | Workaround / status | Verify |
|---|-----|-----|--------|---------------------|--------| |---|-----|-----|--------|---------------------|--------|
| **G1** | **Per-user OAuth on the MCP connector unconfirmed.** Agentforce MCP connectors authenticate via Named/External Credentials. The platform **Per User** identity type (OAuth 2.1 Browser Flow) exists, but it's not documented that an MCP *connector* can bind **Per User** vs only a **Named Principal**. | **C** | If only Named Principal: all tool calls share one service identity → breaks per-user `sub`, ABAC Gmail isolation, and the trifecta guarantees. | **D4:** wrap MCP tools as **Apex / External Service actions** using a **Per-User External Credential (OAuth Browser Flow → Cognito)** — GA, gives the real-user JWT. Use native MCP connector only once per-user binding is confirmed. | SF MCP guide + Named Credentials release notes; test a Per-User external credential end-to-end | | **G1** | **RESOLVED 2026-06-11 (research wf_1bf9e142).** Per-user OAuth Browser Flow on the **native custom remote-MCP connector is unconfirmed**; documented per-user identity exists only for SF-**hosted** MCP. | **C→ mitigated** | If we'd relied on the MCP connector and it bound only a Named Principal: per-user `sub`, ABAC Gmail isolation, and trifecta all break. | **Decided (D4):** do NOT use the native MCP connector for the per-user hop. Use **GA External Service (OpenAPI)/Apex actions + Per-User OAuth Browser Flow External Credential → Cognito** (per-user OAuth is GA, ships in `UserExternalCredential`). | In-org: build one ES action on a Per-User Browser Flow cred → confirm first-call consent, real `sub` reaches the server, and token auto-refresh (§6 verify list) |
| **G2** | **Custom remote MCP client is Beta** (Pilot Jul 2025 → Beta Jan 2026). Salesforce-*hosted* MCP is GA (Apr 2026) but that's SF-hosted, not our remote servers. | **C** | Schedule/stability risk for the native-MCP path. | Same Apex/External-Services fallback (GA) as G1 covers it; or wait for remote-MCP GA. | SF release notes for remote-MCP GA date | | **G2** | **RESOLVED 2026-06-11.** Custom remote MCP client is **Beta** (Pilot Jul 2025 → Beta Jan 2026); SF-*hosted* MCP is GA (Apr 2026) but that's not our remote servers. | **C→ avoided** | Schedule/stability risk on the native-MCP path. | **Avoided by D4** — the GA ES/Apex action path is the per-user transport; the Beta MCP connector is off the critical path. Revisit native MCP once remote-MCP per-user binding reaches GA. | SF release notes for remote-MCP GA date |
| **G3** | **Trust Layer masking may over-mask.** Agentforce Trust Layer can mask PII; legacy Alex **deliberately left vendor names/contacts unmasked** (lookup is the bot's job). | M | Vendor lookups could be degraded if Trust Layer masks names. | Configure Trust Layer masking to exclude names/contacts; keep MCP-layer redaction authoritative for bank/routing/card/SSN (design.md §2.5). | Trust Layer data-masking config | | **G3** | **Trust Layer masking may over-mask.** Agentforce Trust Layer can mask PII; legacy Alex **deliberately left vendor names/contacts unmasked** (lookup is the bot's job). | M | Vendor lookups could be degraded if Trust Layer masks names. | Configure Trust Layer masking to exclude names/contacts; keep MCP-layer redaction authoritative for bank/routing/card/SSN (design.md §2.5). | Trust Layer data-masking config |
| **G4** | **Loss of free-text search over WO comments** (old KB feature) — Data Libraries are unstructured-only, WO/PO are structured MCP lookups. | L | Can't fuzzy-search WO comment text. | Lookup-by-id via MCP tools; or a dedicated retriever over a comment text export if demand appears. | — | | **G4** | **Loss of free-text search over WO comments** (old KB feature) — Data Libraries are unstructured-only, WO/PO are structured MCP lookups. | L | Can't fuzzy-search WO comment text. | Lookup-by-id via MCP tools; or a dedicated retriever over a comment text export if demand appears. | — |
| **G5** | **Embedding model not selectable** — Data Cloud uses Salesforce-managed embeddings (vs legacy Titan Embed V2 1024-dim). | L | Less control over retrieval tuning. | Accept managed embeddings; tune chunking. | Data Cloud index config options | | **G5** | **Embedding model not selectable** — Data Cloud uses Salesforce-managed embeddings (vs legacy Titan Embed V2 1024-dim). | L | Less control over retrieval tuning. | Accept managed embeddings; tune chunking. | Data Cloud index config options |
| **G6** | **BYOLLM-as-Atlas-planner unconfirmed.** AWS-Hosted Claude Sonnet 4 is confirmed to power Atlas; whether a **BYOLLM** Bedrock endpoint can be the agent *reasoning* model (not just prompt templates/Models API) is unclear. | M | May not get our-account Bedrock + our guardrail on the planner path. | Fall back to **AWS-Hosted Claude Sonnet 4** managed option (same family). | supported-models doc; test BYOLLM as agent model in Setup | | **G6** | **RESOLVED 2026-06-11 (research wf_1bf9e142): BYOLLM cannot drive the planner.** Only Salesforce Default / AWS-Hosted options drive the Atlas reasoning engine; BYOLLM is custom-action-only and still routes through SF's Models API/Trust Layer. | M→ resolved | Our-account inference + our guardrail are **unsatisfiable on the planner path**. | **Decided (D5):** use **AWS-Hosted Claude** as the planner; move our guardrail + PII redaction to the **MCP/action layer** (revises D11); rely on the Trust Layer for planner-path moderation. Note AWS-Hosted model is drifting Sonnet 4 → 4.6/Haiku 4.5 (May 2026). | In-org: confirm the reasoning-model selector offers only Default/AWS-Hosted; confirm current AWS-Hosted model name |
| **G7** | **Amazon/AMOC corpus is stale** ("migrated from BookStack, may need updating") and access-restricted (AMOC comms = Adam & Robert only). | M | Agent could give outdated Amazon-site guidance. | Audience-restrict the AMOC topic; flag content as stale; re-author before exposing widely. | Notion *AMOC* `33a2ecdd…8162` currency | | **G7** | **Amazon/AMOC corpus is stale** ("migrated from BookStack, may need updating") and access-restricted (AMOC comms = Adam & Robert only). | M | Agent could give outdated Amazon-site guidance. | Audience-restrict the AMOC topic; flag content as stale; re-author before exposing widely. | Notion *AMOC* `33a2ecdd…8162` currency |
| **G8** | **SA8000 docs + employee handbook + company policies missing** from Notion (referenced as KB inputs, not found). | M | SA8000/compliance + HR Q&A **blocked**. | **Blocked pending content authoring** — author, stage in S3/Drive, ingest into Ops Knowledge Data Library; until then the agent must decline (without suppressing legitimate misconduct questions). | design.md corpus notes; locate any S3/Drive originals | | **G8** | **SA8000 docs + employee handbook + company policies missing** from Notion (referenced as KB inputs, not found). | M | SA8000/compliance + HR Q&A **blocked**. | **Blocked pending content authoring** — author, stage in S3/Drive, ingest into Ops Knowledge Data Library; until then the agent must decline (without suppressing legitimate misconduct questions). | design.md corpus notes; locate any S3/Drive originals |
| **G9** | **Agentforce + Data Cloud licensing / Einstein-Request consumption.** | M | Cost; BYOLLM cuts ~30% of Einstein Requests but Data Cloud + Agentforce licensing still applies. | Budget; BYOLLM to reduce request spend. | Salesforce contract / Einstein Request limits | | **G9** | **Agentforce + Data Cloud licensing / Einstein-Request consumption.** | M | Cost; BYOLLM cuts ~30% of Einstein Requests but Data Cloud + Agentforce licensing still applies. | Budget; BYOLLM to reduce request spend. | Salesforce contract / Einstein Request limits |
@ -454,6 +490,13 @@ sources (§Sources). The **specific** per-user binding for MCP connectors is the
## 6. Open decisions for Adam (with recommendation) ## 6. Open decisions for Adam (with recommendation)
> **STATUS — all resolved 2026-06-11. See §0.1 for the committed resolutions and basis.** Summary: (1) surface +
> licensing **accepted**; (2) reasoning model = **AWS-Hosted Claude** (BYOLLM ruled out for the planner);
> (3) **D3 accepted** (finance stripped from Lauren Exec); (4) per-user auth = **ES/Apex actions + Per-User
> Browser Flow → Cognito** (native MCP connector off the per-user path); (5) corpus authoring (G8) **deferred —
> fund when needed**. The hands-on verify-in-org tests below remain the build-time gate for #2 and #4. Original
> recommendations retained for the record:
1. **Surface + licensing.** Confirm **Agentforce Employee Agents in Slack** as the surface and accept Agentforce 1. **Surface + licensing.** Confirm **Agentforce Employee Agents in Slack** as the surface and accept Agentforce
+ Data Cloud licensing/Einstein-Request cost (G9). *Recommend: yes* — Slack is already our hub and only + Data Cloud licensing/Einstein-Request cost (G9). *Recommend: yes* — Slack is already our hub and only
Employee Agents deploy there; it gives the multi-agent trust-tier mapping design.md §12 wants. Employee Agents deploy there; it gives the multi-agent trust-tier mapping design.md §12 wants.
@ -474,6 +517,21 @@ sources (§Sources). The **specific** per-user binding for MCP connectors is the
Lower-stakes confirmations: new `sh-agentforce` repo (D9, recommend yes); identity provisioning from Google Lower-stakes confirmations: new `sh-agentforce` repo (D9, recommend yes); identity provisioning from Google
Groups to reconcile the two control planes (G11, recommend SCIM). Groups to reconcile the two control planes (G11, recommend SCIM).
**Verify-in-org gate (do these spikes in Phase 0 before building on the decisions — from research wf_1bf9e142):**
1. **(Auth, highest priority)** Build one **External Service (OpenAPI) action** on a **Per-User OAuth Browser
Flow External Credential** pointed at Cognito; invoke it from an Agentforce agent **running in Slack** and
confirm: (a) the end user gets the interactive "Allow Access" consent on first call, (b) the per-user token
(`UserExternalCredential`) is sent so the tool server sees the real `sub`, (c) token auto-refresh works.
Slack-side consent UX is undocumented in verified sources — observe it directly.
2. **(Auth, native path check)** Register a test custom remote MCP server and inspect the auto-generated
External Credential — confirm whether its identity type can be set to **Per-User Browser Flow** vs only
**Named Principal**. If Per-User is offered, native MCP becomes a future option; until then D4 (ES/Apex) stands.
3. **(Auth, limits)** Confirm headless/automated invocation behavior (Browser Flow needs interactive first-auth
per user), per-org limits on number of ES/Apex actions, and added latency vs native MCP.
4. **(Model)** Confirm the reasoning-engine selector (Setup → Agentforce Agents; `model_config` in Agent Script)
offers only **Salesforce Default** / **AWS-Hosted**, and confirm the current model name behind AWS-Hosted
(Sonnet 4 vs 4.6 vs Haiku 4.5).
--- ---
## Sources (platform claims verified via web search, 2026-06-11) ## Sources (platform claims verified via web search, 2026-06-11)