hamsa software
← All articles
Automation7 min read

Reconciling the CRM record that already exists

A useful runbook says how to recognise the case, what evidence permits the action, when to stop and what proves completion. A CRM timeout gives those instructions something concrete to do.

Two rectangular shapes are joined by three short stitches, representing reconciliation between an existing remote record and local knowledge.

The instruction arrives without its author

“Rerun the job” is a surprisingly large decision to leave in a runbook. In a CRM-create timeout, the destination may already hold the customer while the local record has no result. The person taking over needs a way to recognise that situation before following the instruction and creating another customer. The useful procedure starts with what to check, not with a command whose safety its absent author was expected to explain.

In this invented case, the local operation says outcome_unknown and has no external identifier. The destination may have created the record before the reply was lost. Depending on the provider’s contract, another attempt could retrieve the intended result or make a duplicate. A short instruction can still handle the case, but it needs to distinguish those possibilities before asking someone with production access to act.

Google’s SRE guidance identifies clear escalation paths and well-defined operational procedures as resources supporting people on call. [1] The small runbook below applies that principle to a specific synthetic case. It is not a universal CRM recovery command: it assumes a destination with a trustworthy lookup by the stable operation reference, and a local reconciliation action designed for this purpose.

Begin with recognition, not a command

The entry condition is precise: operation crm-create:C17, correct tenant and environment, state outcome_unknown, external_id absent and local revision 4. The operator needs read access to the operation and the authorised destination lookup, plus permission for the local reconciliation action. None of those permissions should be obtained by borrowing an administrator’s token pasted into the runbook. Link to the approved access path and the duty role instead.

Some nearby cases need another procedure. This is a create, not a customer update; an unanswered outcome, not a known validation rejection. A local link to a different remote customer is a reason to stop, not overwrite it until the screen looks right. Give the operator the appropriate escalation route and the identifiers to take with them. That leaves a useful boundary they can recognise without having to infer what the author probably meant.

Keep a short read-only summary before any mutation: local operation, customer, tenant, submitted identity fields, current revision and known provider reference. The person should be able to check that they are investigating the right object. A production screen that differs unexpectedly from the documented fields is another stop condition, not a reason to infer which unfamiliar button probably does the same thing.

The procedure also needs an escalation owner and the team’s maintained contact route. While waiting, the operator should keep the operation held, prevent another uncontrolled attempt and preserve its unresolved status for the person handling the customer-facing work. Naming a general role without a functioning duty arrangement leaves the same recovery decision unowned when the integration’s author is unavailable.

Follow the existing record branch

The first decision is a lookup by the stable operation reference, not a broad search for a similar company name. In this fixture, the synthetic destination result binds operation crm-create:C17 to customer C17 and remote identifier X77. Verify the relevant tenant and identity fields under the actual provider contract. An address or display name alone may identify several records, so a plausible-looking match is not sufficient evidence to link one.

Exactly one trustworthy matching result permits the chosen recovery branch: record X77 locally as the result of this operation. Do not issue another remote create. The local action changes outcome_unknown to reconciled and advances revision 4 to 5 only if the expected state, missing link and revision still hold. PostgreSQL’s conditional UPDATE model supports expressing such a precondition with the mutation and inspecting whether a row changed. [2]

If the conditional update changes no row, read the operation again. Someone else may already have reconciled it, or a background process may have advanced the revision while the lookup was being checked. The zero is telling the operator that this transition no longer fits, rather than asking them to force it through. Compare the current state with the procedure before deciding whether any work remains.

If the lookup returns no result, several results or a mismatched identity, this branch stops. Absence in one search is not automatically proof that no create was accepted or remains in flight. AWS’s idempotency discussion explains why intent and uncertain outcomes matter to retry design. [3] The real integration needs its documented provider-specific path; a generic runbook should not turn a failed lookup into permission to mint a new identity and try again.

The useful instruction is not simply rerun

Original CRM-create recovery procedure, assuming the destination supports a trustworthy lookup by the stable operation reference. The chosen branch links an existing remote record instead of creating another one.

Follow the labelled arrows. On a narrow screen, scroll sideways if needed.

The useful instruction is not simply rerunConfirm C17 / revision 4 and scope. Use the correct environment and tenant. Local crm-create:C17 is outcome_unknown with no external_id. Trustworthy destination lookup. Query by the stable operation reference under the destination’s supported contract. Exactly one matching result: X77. The synthetic result binds the same operation and customer C17. Stop and use the named escalation path. No/multiple matches, mismatched identity, an existing different link or a changed local revision prohibit guessing. Conditional local revision 4 → 5. Record external_id X77 and reconciled. No remote create call is performed. Read back reconciled / X77 / revision 5. Verify the link and retain evidence of the lookup and action, rather than relying only on a command exit status. From Confirm C17 / revision 4 and scope to Trustworthy destination lookup: Scope and operation established. From Trustworthy destination lookup to Exactly one matching result: X77: Exactly one identity-bound match. From Trustworthy destination lookup to Stop and use the named escalation path: Evidence missing or conflicting. From Exactly one matching result: X77 to Conditional local revision 4 → 5: Local guards still match. From Conditional local revision 4 → 5 to Stop and use the named escalation path: Guard fails or link changed. From Conditional local revision 4 → 5 to Read back reconciled / X77 / revision 5: Conditional transition succeeds.Scope andoperationestablishedExactly oneidentity-bound matchEvidence missing orconflictingLocal guardsstill matchGuard fails or linkchangedConditionaltransitionsucceedsConfirm C17 / revision4 and scopeUse the correct environmentand tenant. Localcrm-create:C17 isoutcome_unknown with noexternal_id.Trustworthy destinationlookupQuery by the stable operationreference under thedestination’s supportedcontract.Exactly one matchingresult: X77The synthetic result bindsthe same operation andcustomer C17.Stop and use the namedescalation pathNo/multiple matches,mismatched identity, anexisting different link or achanged local revisionprohibit guessing.Conditional localrevision 4 → 5Record external_id X77 andreconciled. No remote createcall is performed.Read back reconciled /X77 / revision 5Verify the link and retainevidence of the lookup andaction, rather than relyingonly on a command exitstatus.
The downloadable fixture executes only the local in-memory SQLite branch. Destination X77 and all identifiers are synthetic; no CRM lookup or remote mutation was performed. A real runbook must use the destination’s actual supported contract.

Show what the recovery proves

The downloadable local branch uses the authored destination result to link X77 at revision 5. Repeating the old revision-4 transition changes nothing. Read those outcomes together: one records the justified relationship, while the other preserves it against an obsolete recovery request. The in-memory database does not query or write a CRM. Its useful check is narrower and inspectable: when the expected state, missing link or revision no longer holds, this recovery branch must stop rather than overwrite the current relationship.

The runbook’s final verification should read back the same business identity, recorded remote link and final state. Where appropriate, inspect the destination through the supported read path too. The expected result is one linked customer record for the original intention, not merely an exit code of zero. Capture the evidence needed for the operational record without dumping private customer contents into a general incident channel.

Keep the original uncertain attempt visible after the link is repaired. Its missing result may explain a recurring gap in the integration, or why the local completion time is later than the destination’s creation time. Reconciliation establishes the current justified relationship; it does not rewrite the earlier uncertainty out of existence. The next investigator can then see both why X77 is linked now and why somebody had to recover the link at all.

Define what to do if read-back after reconciliation shows another link or an unexplained state: stop further attempts, retain the identifiers and escalate through the supported route. Repeating the mutation could erase evidence of the race or incorrect assumption. The procedure needs this branch even after an apparently successful local action, because the completion claim depends on reading the expected relationship back from the system.

Reconciled describes a justified link, not a rewritten history

The CRM fixture’s successful local branch preserves the original uncertain attempt.

Scroll sideways to see all columns.

VerificationExpected resultLimit
Operation/customer bindingcrm-create:C17 belongs to customer C17Not a name-only remote match
Conditional local actionRevision 4 outcome_unknown becomes revision 5 reconciledNo new remote create performed
Read-backExternal identifier X77 remains linkedA zero exit code alone is insufficient
Unexpected link or stateStop and retain identifiersDo not repeat mutation until display looks right
The program uses an authored destination result and an in-memory database; no actual CRM recovery is claimed.

Practise the document where mistakes are cheap

Ask someone who did not write the integration to use the runbook against safe synthetic states: the existing X77 case, no trustworthy match, multiple matches, already reconciled and a changed revision. Watch where the document asks them to infer missing context. Its purpose is to improve the instructions before a real incident supplies the stress.

Keep commands and application links specific to the maintained implementation. Show required parameters, whether a step is read-only and the expected shape of its result. Separate specimen commands from live commands so a copied example cannot silently target the wrong environment. A long catalogue of every possible administrative tool is less useful than a short supported path with clear prerequisites and stop conditions.

Revisit the runbook when the integration’s states, access route or destination contract changes, and give that work an owner. A recent safe exercise or substantive review is more informative than a fresh formatting date. An older procedure may still be right; a document edited yesterday may describe a button that no longer exists. Maintaining this one means checking that its decision path still finds and justifies the original customer link.

For this branch, the person taking over can finish with crm-create:C17 linked to verified X77, reconciled at revision 5, without issuing a remote create. If the lookup or local conditions differ, they have a stop route with the relevant identifiers ready. That is the useful independence a runbook can provide. The integration’s author does not need to be present to explain which uncertainty the next command would otherwise turn into another customer.

Working on a workflow like this? Hamsa helps finance and operations teams connect their tools and handle the exceptions, starting with one workflow.

See the Payment Operations Pilot

References & further reading

Primary sources behind this article. Living documentation may change.

  1. Google SRE: clear escalation paths and operational procedures
  2. PostgreSQL: conditional UPDATE and affected results
  3. AWS Builders Library: retry intent and uncertain results
Hamsa Jama

Practical engineering. A human perspective.

More about Hamsa Software and the person behind it. Editorial notes.

A few more things
worth a read.

Back to the reading room
Automation6 min read

A budget that three workers can share

Enforce task limits through atomic reservations and repeat-safe settlement, including the uncomfortable case where a timed-out operation may still be spending.

Automation7 min read

What exactly did that approval authorise?

Bind an assistant’s approval to the action, target and material revision, then enforce that binding when the write happens.