Zendesk and Salesforce Drift Audit
MaintainZendesk organization external_ids, user memberships, and ticket attribution drift from Salesforce over time. You need to audit the whole surface, review grouped exceptions by account, and apply only 4 safe Zendesk-side repairs — with receipts for every attempted, applied, blocked, and skipped action.
The Slack Message
CSMs are getting escalations because tickets are landing on the wrong account team. I already found 3 customers with duplicate Zendesk orgs, and some end-users are assigned to the wrong org entirely. Can you figure out how bad this actually is across every account and tell me what's safe to fix in Zendesk without touching Salesforce?
The Prompt
Kicked off from the terminal. The demo flag lets ops see the artifact shape before connecting a live Zendesk token.
We think Zendesk is drifting from Salesforce for some customers. I need to: 1. Audit every Salesforce account against its Zendesk org, users, and tickets. 2. Get one grouped triage file I can share with support ops. 3. See the fix plan with which actions are safe-to-apply and which are blocked. 4. Apply only the safe Zendesk-side actions. Never touch Salesforce. Never mutate tickets. Use --demo first so I can see the artifact shape before we connect the live Zendesk.
The grouped exception file is the product
This is not “magic sync.” Gremlin detects drift across 12 issue codes, groups the exceptions by Salesforce account in exceptions_by_account.csv, and prepares a fix_plan.json with a stable plan_hash. Audit → review → dry-run → apply. Only 4 safe Zendesk-side actions ever run. Salesforce and tickets are never mutated.
Core Workflow
Audit, detect, triage, dry-run, apply. Every step is supervised.
Audit drift
Run g-gremlin zendesk drift audit against a Salesforce reference CSV and Zendesk credentials (or --demo for zero-auth fixtures).
Detect across 3 layers
12 categorized issue codes: 6 org-level, 4 user-level, 2 ticket-level. Ticket codes are detection-only.
Grouped triage
exceptions_by_account.csv: one row per Salesforce account with prepared_action_count, blocked_action_count, and top_blocked_reasons.
Dry-run apply
Revalidate preconditions against the hashed fix_plan.json. No writes unless --apply is passed with a matching --confirm-plan-hash.
Live apply with caps
Only 4 safe actions run: set_org_external_id, add_org_domain, assign_user_to_org, move_user_to_org. Caps enforced up front.
"Three layers to audit: orgs, users, and tickets. The demo loader uses bundled fixtures that mirror a real run, so I'll start there before anyone connects a live Zendesk token."
"Step 1: g-gremlin zendesk drift audit --demo. Step 2: review exceptions_by_account.csv. Step 3: identify blocked accounts and why. Step 4: dry-run the fix plan. Step 5: live apply the safe actions with caps. Step 6: rerun the audit to prove the drift count dropped."
"5 prepared actions, 4 blocked. The blockers are 2 duplicate_external_id, 1 domain_belongs_to_other_org, and 1 user_domain_ambiguous. Those cannot be auto-fixed. They need a human to resolve the ambiguity in Zendesk before any safe action can be prepared for those accounts."
Audit done. 5 safe actions ready. 2 accounts need Zendesk-side review before their drift can be repaired. 1 account is ticket-only and does not generate writes.
exceptions_by_account.csv
One row per Salesforce account. Support ops opens this file in a spreadsheet, uses the prepared_action_count and blocked_action_count columns to decide which accounts go through, and resolves the blocked ones in Zendesk before re-running the audit.
| sf_account_id | account_name | total | prepared | blocked | top_issue_codes | top_blocked_reasons |
|---|---|---|---|---|---|---|
| 001ACME001 | Acme Healthcare | 1 | 1 | 0 | org_missing_external_id | |
| 001ACME002 | Acme Labs | 3 | 0 | 2 | org_duplicate_external_id | duplicate_external_id |
| 001ACME003 | Acme Biotech | 1 | 0 | 1 | org_domain_attached_elsewhere | domain_belongs_to_other_org |
| 001ACME004 | Acme Retail | 2 | 2 | 0 | org_missing_expected_domain, user_missing_expected_membership | |
| 001ACME006 | Acme Studios | 2 | 0 | 0 | ticket_org_mismatch |
Green rows are safe-to-apply. Red rows are blocked in Zendesk until ops resolves the ambiguity. Yellow rows are ticket-only and never generate write actions.
"Support ops reviewed the 2 duplicate_external_id cases in Zendesk and picked the surviving orgs. The ambiguous domain and user cases are assigned to a human. Now the 5 prepared actions should all still pass preconditions. Dry-run first to re-validate."
"Dry-run clean. Applying live with --apply and --confirm-plan-hash. Caps are --max-actions 25 and --max-per-account 3 by default."
4 Zendesk-side repairs applied. 1 stale row skipped explicitly. 0 Salesforce writes (by design). 0 ticket mutations (by design). Full receipt in apply_receipt.json with source_plan_hash cross-check.
Safety Guarantees
Requirements
Zendesk API token
Read + narrow write scope (orgs, users, memberships)
Salesforce reference CSV
sf_account_id, account_name, and a domain source
Gremlin CLI with zendesk drift
init, audit, trace, apply commands
--demo mode for dry-runs
Works with zero auth using bundled fixtures
Results (demo run)
By design. Salesforce stays read-only reference input.
Ticket issues are detected but never trigger writes.
Try This Workflow
Start with the demo. No Zendesk token and no Salesforce connection required to see the full artifact set.
Related guide: How to Integrate Salesforce and Zendesk Without Breaking Ownership and Reporting