Salesforce · Tableau Next · SE Track

What deploys onto an attendee org.

Every artifact below is Sandbox-grade metadata, deployed via the standard sf CLI against the attendee's OrgFarm scratch. No production tenants touched.

Agent Astro pointing

1.What deploys onto an attendee org

Every artifact below is Sandbox-grade metadata, deployed via the standard sf CLI against the attendee's OrgFarm scratch. No production tenants touched, no cross-org access, no shared state.

Deploy invocation (attendee-facing, unmodified)
# Attendee session start — invoked by the `cold-open` skill in Claude Code
sf org login web # 2 clicks in a browser popup; produces a session for the current OrgFarm
sf package install --package 04tJ80000011MXvIAM --wait 10 --no-prompt
sf project deploy start --source-dir force-app/ --wait 10
sf apex run --file bootstrap/assign-perms.apex

2.OAuth scope ask (with curl evidence)

The 25 industry data kits load row data through the CDP tenant Bulk-Ingest API. That endpoint refuses a token minted without cdp_ingest_api scope. This is the only outstanding platform dependency.

What we’re asking

Three additional OAuth scopes added to the shipped PlatformCLI Connected App (API name PlatformCLI, label “Salesforce CLI”) in the Sales Cloud Vibe Coding OrgFarm image spec:

  • cdp_ingest_api — Access CDP Ingestion API
  • cdp_query_api — Access CDP Query API
  • cdp_profile_api — Access CDP Profile API

Set path: Setup → App Manager → PlatformCLI → Manage → Edit Policies → Selected OAuth Scopes → add three → Save. Then bake into the image spec so all future pulls inherit.

Why — live evidence, workshoplwc2, 2026-07-13
# Token from `sf` CLI session, no CDP scopes
$ TOKEN=$(sf org display --json | jq -r '.result.accessToken')
$ TENANT="gjrg8nzsgfqw0n3dg82gcnbqg8.c360a.salesforce.com"

$ curl -X POST "https://$TENANT/api/v1/ingest/jobs" \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"object":"CK_Industry_Reviews","operation":"upsert"}' \
    -w "\nHTTP %{http_code}\n"

HTTP 400
# empty body — CDP tenant rejects under-scoped token with no error body

The same POST after the scope grant returns HTTP 201 with a job ID. Verified end-to-end against workshoplwc2 during the 8-path research (Path A).

What we tried already (all closed)
ApproachResult
Metadata API ConnectedApp deploy with CDP scopes Rejected. Error: 'CdpIngestApi' is not a valid value for the enum 'ConnectedAppOauthAccessScope'. Enum does not expose any variant (CdpIngestApi, DataCloudIngestApi, etc.). Verified on API v67.
2GP scope grant via CK-DataCloud-Access Same enum rejection. Package deploys successfully — perm-set + PSL layer works — but the ConnectedApp scope layer is unreachable through packaging metadata.
sfdatakit__DeployDataKitComponents flow Schema-only. Deploys DMO shells + mappings from an installed managed package. Zero CSV load path. Confirmed via reverse-engineering hackathon-Q’s apex_knowledge_connector.py.
Direct sObject INSERT into *__dll INSUFFICIENT_ACCESS_OR_READONLY. Verified with GenieAdmin perm set assigned. DLO sObjects are createable=false at the platform layer.
Bulk API 2.0 against DLO sObjects No create access. describeSObjects() reports createable=false. Bulk 2.0 job creation returns FEATURE_NOT_ENABLED.

Full 8-path research (Paths A–H, each with curl + HTTP status): /vibecoding/why/ and docs/dc-ingestion-research-2026-07-13.md.

3.What happens when scope IS granted (technical flow)

Four programmatic stages against the CDP tenant. All headless. Idempotent by name. Documented Path A in the research doc.

# Stage 1: create connector — HTTP 201, returns tenantSpecificEndpoint
POST /services/data/v67.0/ssot/connections
{ "connectorType": "IngestApi", "name": "ck_industry_reviews", "label": "CK Reviews" }
→ 201  { id, name, tenantSpecificEndpoint }

# Stage 2: register schema — HTTP 200
PUT /services/data/v67.0/ssot/connections/{id}/schema
{ "schemas": [ { "schemaType": "IngestApi", "name": "Reviews",
    "label": "Reviews", "fields": [ ... ] } ] }
→ 200

# Stage 3: create data stream — HTTP 201, auto-materializes DLO
POST /services/data/v67.0/ssot/data-streams
{ "datastreamType": "INGESTAPI", "connectorDetails": { "events": [...] } }
→ 201

# Stage 4: bulk-ingest rows — HTTP 202, then chunked PUT of CSV parts
POST https://{tenantSpecificEndpoint}/api/v1/ingest/jobs201  { jobId }
PUT  /api/v1/ingest/jobs/{jobId}/batches  # CSV body202
PATCH /api/v1/ingest/jobs/{jobId}  { "state": "UploadComplete" }
→ 200
Timing per kit

~90 sec per kit end-to-end. 25 kits at parallelism 3 = ~15 min for the full fleet on a fresh org.

Idempotency

Connector already exists → reuse the ID from GET /ssot/connections?connectorType=IngestApi. Schema field collision → PATCH the schema. Safe to re-run.

4.Blast radius + reversibility

This is the core concern — and it is bounded by design. Every scope, every write, every artifact is contained to the attendee's 15-day scratch org.

SCOPE
The scope grant is on the OrgFarm image’s built-in PlatformCLI Connected App — not a customer-installed app. It applies to attendee scratch orgs pulled from that image. Production tenants inherit nothing.
EXPIRY
Attendee scratch orgs are 15-day OrgFarm scratches (edition=Enterprise, provisioned via HOT Pass). Auto-expire. No renewal path attendee-side.
DATA PATH
The token minted by sf org login web is scoped to the attendee’s single org. It cannot reach any non-attendee-namespaced org. Every write is org-local. No cross-tenant traversal.
REVERSAL
Setup → App Manager → PlatformCLI → Edit Policies → unselect 3 scopes → Save. Zero data loss. Zero migration. New tokens minted after the change simply lack the scope. Existing tokens expire on their normal 2h refresh window.
AUDIT
Every meaningful event is queryable on the attendee org: PackageInstallRequest (2GP install), PermissionSetAssignment (perm bootstrap), LoginHistory (OAuth handshakes), ApexClass.LastModifiedDate. Standard Salesforce audit stack, unmodified.
NAMESPACE
The cold-open skill writes ~/.workshop/attendee.json at session start. All authored assets are prefixed with that namespace — sheets, dashboards, calc fields, LWC assets. Re-running a workshop never collides. The panic-reset skill tears down that namespace via a targeted destructiveChanges.xml deploy in under 60 sec.
Reversal — concrete curl
# List active tokens for the Connected App
$ curl -s "$INSTANCE_URL/services/data/v67.0/query" \
    -H "Authorization: Bearer $TOKEN" \
    --data-urlencode "q=SELECT COUNT() FROM OauthToken WHERE AppName='Salesforce CLI'"

# Revocation is Setup-UI; API path via ToolingApi.ConnectedApplication:
$ curl -X PATCH "$INSTANCE_URL/services/data/v67.0/tooling/sobjects/ConnectedApplication/$ID" \
    -H "Authorization: Bearer $TOKEN" \
    -d '{"OauthConfig": {"Scopes": ["Api","RefreshToken"]}}'  # CDP scopes dropped

5.Precedent

This pattern is not novel. Two internal Salesforce precedents already ship elevated scopes into demo / workshop orgs through 2GP.

PackageVersion IDWhat it doesNamespace
QBranch Connector 04tWs000000hDYHIA2 OAuth connector for the Q Branch Generator. Beta, unpromoted. Uses ECA-based OAuth (documented that ECA scopes are not packagable — same blocker we hit). none
QBranch Demo Metadata 04tJ8000000kaPgIAI B2C/B2B Sales & Service Cloud demo metadata (Customer Segment, Loyalty Tier, LTV, RecordType scaffolding). Promoted. Currently installed across QBranch demo orgs. none
CK-DataCloud-Access ours 04tJ80000011MXvIAM Perm-set + PSL assignment for Data Cloud user role in Vibe Coding workshop orgs. 83% code coverage, verified against workshoplwc2. none
sfdatakit Salesforce-internal DMO schema deploy pattern used by Service Insights. Same “deploy metadata to attendee scratch, expect it to Just Work” contract. sfdatakit

Full audit of the hackathon-Q pattern (2GP file layout, install lifecycle, InstallHandler behavior on first-install-vs-upgrade): docs/q-hackathon-2gp-audit.md.

6.Timeline

Decision needed T-8. Everything downstream is already built and dependency-documented.

2026-07-13 — today (T-9)
Feature-complete, dependency documented. 142 LWCs shipped, 25 industry kit schemas built, 8-path Data Cloud ingest research published, 2GP 04tJ80000011MXvIAM promoted, ck-datacloud-access verified against workshoplwc2.
2026-07-14 — T-8
Decision needed from OrgFarm on scope grant. Antoine + peers. Ask is in docs/antoine-ask.md. Single Setup-UI change, baked into image spec for future pulls.
2026-07-15 — T-7
If approved, post-scope-grant-run.sh fires against a fresh OrgFarm pull. 25 kits install in ~15 min at parallelism 3. Fleet dashboard confirms row counts.
2026-07-20 — T-2
Dress rehearsal against fresh OrgFarm pull with an attendee-role user. Full 20-min workshop flow end-to-end.
2026-07-22 — Dallas launch
30-45 practitioners from HCSC, Toyota Financial, H-E-B, AT&T, Children’s Health, and peers. 9 AM – 1 PM CT.
Fallback if scope grant slips past T-5

Workshop runs on the Sales Cloud SDM alone (12 DOs, 16 metrics, 35 calc measurements) — that story is complete without the industry kits. The kits become a T+30 follow-up push once the scope is granted. See docs/facilitator-scope-fallback.md for the rescoped run-of-show.

7.Read the source

Every claim above is backed by a committed artifact. Nothing on this page is speculative unless flagged.