River
Y CombinatorBacked by Y Combinator
FREE TEMPLATE

System of Record Map Template

Every field's owner checked against who really last wrote the record, with the sync rules read as set and the cycle drawn.

Free download  ·  No account needed

One rep edit on a field the policy assigns to the CRM. Eight syncs, three of them a loop.

TimeSystemValue in the fieldWhat wrote it
Mon 16:12CRMThird-party logisticsA rep types it
Mon 16:14MarketingThird-party logisticsTwo-way mapping, near real time
Mon 18:00WarehouseThird-party logisticsSix-hourly extract, read only
Tue 01:40WarehouseTruckingEnrichment provider overwrites
Tue 02:00MarketingTruckingNightly reverse ETL
Tue 02:03CRMTruckingTwo-way mapping carries it back

Nine hours and fifty-one minutes. Every hop was approved separately and every one is defensible. Sixty edits a week take this route, which is 780 a quarter, and the two events never share a working hour.

Every system of record template is the same table: field, system, owner. Fill it in, circulate it, done. That table is a statement of intent, and intent does not decide the value in the field. A sync rule does, and the rules were set during an implementation years ago by somebody who has left. Of fourteen fields audited at Meridian Freight, seven had a declared owner the modification history contradicts. Four were already correct.

Six of the fourteen sit on a two-way rule, which is not a system of record but the absence of one. The documented behaviour is that the most recent value overwrites whatever is there, so the authoritative system is whichever job ran last. That makes the answer a cadence, and a cadence is invisible in the settings screen. A near-real-time sync loses to a nightly batch every night, so the slowest hop in a loop is usually the one deciding the value.

On Industry, an integration user is the last writer on 2,732 of 3,140 accounts, 87.0%, against a policy assigning the field to sales. The cause is a loop: a six-hourly extract into the warehouse, a nightly enrichment reverse ETL into the marketing platform, and a two-way mapping back. A rep's edit at 16:12 is reversed by 02:03. Sixty edits a week, 780 a quarter, and it pairs with a two-system reconciliation and a field dictionary. A blank propagates too, which emptied one field on 337 contacts in both systems.

The declared owner, and the one the data proves

Fourteen fields, four objects, one book: 3,140 accounts and 18,640 contacts. Every count on these sheets comes from the modification history rather than the configuration.

Field to System Map

Illustrative rows for a fictional freight brokerage, Meridian Freight. The last two columns are what separate this from the usual field-system-owner table: what the evidence says, and whether it agrees.

ObjectFieldDeclared ownerWrite pathsRule as actually setEffective winnerEvidence from the modification historyVerdict
AccountIndustryCRM3Two-wayEnrichment providerIntegration user is the last writer on 2,732 of 3,140 accounts (87.0%)The declared owner is not the owner
AccountAnnual RevenueWarehouse4Two-wayEnrichment providerIntegration user is the last writer on 2,870 of 3,140 accounts (91.4%)Declared to the warehouse, owned by a third party
AccountOwnerCRM2Two-way, forcedWhichever wrote lastThe platform permits only a two-way mapping and requires an exact value matchCannot be made one way. Logged as an exception
AccountPayment TermsBilling2Two-wayWhichever wrote last76 of 3,140 accounts hold a different value in each systemNo owner in practice
AccountMRRBilling3Don't syncBillingCorrect in the CRM. The marketing copy has a median staleness of 34 daysCorrect in one system, silently stale in the other
ContactPhoneCRM1Always use the CRMCRMA person in the CRM is the last writer on 17,932 of 18,640 contacts (96.2%)Correct, and see the blank entry in the conflict log
ContactEmailCRM3Two-wayWhichever wrote last41 of 18,640 contacts hold a different address in each systemNo owner in practice
ContactLifecycle StageMarketing2Don't syncBoth, independently1,148 of 18,640 contacts sit at different funnel positions in the two systemsTwo systems of record and nothing to reconcile them
ContactJob TitleMarketing4Two-wayWhichever wrote last288 of 18,640 contacts differ between systemsVariance accepted and documented rather than fixed
ContactCountryMarketing4Prefer the CRM unless blankCRM when populated604 of 18,640 contacts are blank in the CRM, so the marketing value is pushedWorks as designed, and the only rule here that does
ContactMarketing Contact StatusMarketing1Not syncableMarketingThe platform will not let a sync or a merge set thisCorrect by construction
DealAmountCRM2Always use the CRMCRMNo divergence found in the sampleCorrect
DealClose DateCRM1Always use the CRMCRMNo divergence found in the sampleCorrect
TicketPrioritySupport2One way into the CRMSupportNo divergence found in the sampleCorrect

Six of the fourteen sit on a two-way rule, which means the winner is whichever job ran last. Six have three or more systems able to write them. Seven have a declared owner the history contradicts, and the two worst are the two an enrichment provider touches.

Sync Direction

Cadence and blank behaviour are the two columns nobody records, and both change the answer. Read row by row and every line is defensible, which is exactly why the loop was never caught.

SourceTargetCadenceTriggerFields carriedBlank behaviourIn a cycle withEffective precedence
CRMMarketingNear real timeA record change438 contact and 214 company mappings of 500 allowed per objectA cleared value clears the targetMarketing to CRMLoses to anything writing later
MarketingCRMNear real timeA record changeThe 96 mappings set to two-wayA cleared value clears the target both waysCRM to marketingLoses to anything writing later
WarehouseMarketingNightly 02:00A schedule11 enrichment fieldsA blank in the source leaves the target aloneCRM, then marketing to CRMWins on every field it carries
CRMWarehouseEvery 6 hoursA scheduleFull table extractn/aWarehouse to marketingRead only. Never writes back
BillingCRMHourlyA schedule6 commercial fieldsOverwrites with blanksNoneWins on its 6 fields
SupportCRMNear real timeA record change4 fieldsOverwrites with blanksNoneWins on its 4 fields
Web formsMarketingOn submissionA person14 fieldsBlanks are ignored on submissionMarketing to CRMLoses to the nightly enrichment
EnrichmentWarehouseNightly 01:40A schedule11 fieldsReturns no value for 408 of 3,140 accountsWarehouse to marketingWins wherever it returns a value, 87.0% of accounts

The loop is three hops: a read-only extract into the warehouse, a nightly reverse ETL into the marketing platform, and a two-way mapping back into the CRM. It is a property of the composition rather than of any hop, and nobody owns the composition. The nine edits a week that survive are the accounts the provider returns nothing for, which is why the survival rate and the coverage gap are the same number.

Known Conflict Log

The recurring column is the most useful one on the sheet. A conflict caused by an event is a repair. A conflict caused by a rule comes back next week.

FoundFieldThe two valuesCauseRecordsResolutionRule changed toRecurring
2026-03-09Account.IndustryThird-party logistics against TruckingThe nightly enrichment writes last and the mapping is two-way2,732 of 3,140Enrichment moved to its own field as a provider estimate. Rep field now one way out of the CRMAlways use the CRMYes, 60 rep edits a week until the rule changed
2026-02-24Contact.PhoneA number against a blankA cleanup blanked malformed numbers, and the rule propagates a deletion as a value337Restored from the pre-cleanup export. Cleanup rewritten to correct rather than clearUnchangedNo. One event, and the rule was right
2026-01-15Contact.Lifecycle StageCustomer against WorkingDon't sync was set three years ago to stop a loop, and both sides drifted1,148Lead Status retired as a funnel field. The marketing platform is now the single authorityOne way out of marketingStructural. Fixed at the source
2026-04-02Account.Annual Revenue4.2m against 11.8mAdjacent fields carry different rules and the enrichment writes last on both2,870 of 3,140Provider value moved to its own field and labelled an estimateDon't syncYes. Same cause as the Industry entry
2026-04-18Contact.EmailTwo different addressesA two-way rule on a field a form and a rep can both write41The form now writes to a secondary field pending verificationPrefer the CRM unless blankYes, at low volume
2026-05-06Account.Payment TermsNet 30 against Net 45A two-way rule on a field the billing system owns outright76Made one way out of the billing systemAlways use billingYes
2026-05-21Contact.Job Title288 records hold different valuesFour write paths and a two-way rule, so the last writer wins each record288Enrichment demoted to a suggestion field. The variance is acceptedTwo-way, retained deliberatelyAccepted variance, documented as such
2026-06-04Account.MRRA current figure against a stale oneDon't sync protected the field, so the second copy simply aged3,140The copy was deleted and replaced with a read-only card reading the billing systemDon't sync retainedNo. Deleted rather than synced

Two entries came from the same cause and neither was a data problem. Two were resolved by splitting a field so a machine and a person each own their own, and one by deleting a copy entirely. A protected copy does not stay correct, it ages, and a stale value that looks live is worse than no value at all.

What the pack does that a field-owner table does not

01

Counts the write paths before naming an owner

A person typing, an internal automation, an inbound integration, a form, a scheduled import, a reverse ETL, an enrichment provider, and the API key somebody issued three years ago. Six of the fourteen fields here turned out to have three or more.

02

Checks the declaration against who really wrote the record

Last-modified-by aggregated across the whole object rather than sampled on three records. An integration user winning 87% of a field the policy assigns to a person is a different problem from one winning 4%, and only the count tells them apart.

03

Treats two-way as the absence of an owner

The most recent value wins, so the authoritative system is whichever job ran last. That is a cadence rather than a policy, and it is why a near-real-time sync loses to a nightly batch every night without anybody noticing.

04

Records what a blank does, per mechanism

On a per-field CRM mapping, clearing a value in the owning system clears it in the other. On the generic sync path, a blank in the winning app changes nothing. Same vendor, opposite behaviour, and neither screen mentions the other.

05

Draws the cycle three defensible syncs compose into

A read-only extract, a nightly reverse ETL, and a two-way mapping. Each was approved on its own merits. Together they route a field back into the system that owns it, and the diagram is what ends the argument in the meeting.

06

Sequences the fix so it does not lose data

Snapshot, then rule change, then a deliberate one-way backfill. A new mapping does not repair existing records, and the first sync on a record with no history for that field can overwrite the newer value with the older one.

How the pack runs

  1. 1

    Send the configuration

    Field exports from each system, the integration and field-mapping settings including the per-field rules, and anything showing who last modified a record.

  2. 2

    Count and read

    Every write path into every field, then every sync rule as it is actually set today, with its cadence and its blank behaviour recorded alongside.

  3. 3

    Test against the data

    Last-writer shares aggregated across each object, plus a direct divergence count per field, so the declared owner either holds up or does not.

  4. 4

    Draw it and sequence it

    The flow diagram with the cycles marked and timed, the policy field by field, and a change plan ordered by blast radius rather than by annoyance.

Frequently asked questions

Is this not just a table of fields and owners?

That table is where it starts and it is the part everybody already has. The difference is the last two columns: who actually last wrote each record across the whole object, and whether that agrees. Seven of fourteen fields here did not, and the counts are what settle it.

What is actually wrong with a two-way sync?

It has no concept of authority in it. The documented behaviour is that the most recent value overwrites whatever is there, so the winner is whichever integration ran last. That turns your system of record into a schedule, and a nightly batch beats a real-time sync every night.

We set a field to don't sync to stop a loop. Is that safe?

It stops the loop and gives you two systems of record instead of none. Nothing errors and nothing surfaces, so the two values simply drift. On the worked example 1,148 contacts ended up at different funnel positions, and the fix was deleting the concept from one side, once the stages themselves were defined.

Will fixing the mapping fix the records already there?

No, and this is where a cleanup becomes an incident. Existing values in a new mapping do not retroactively sync, and the first sync on a record with no prior history for that field baselines on the target's current value. That can overwrite newer data with older.

Can we set a per-field owner on every integration?

No, and the map records which mechanism carries each field for that reason. A generic data sync resolves conflicts with one default app for the whole integration, and leaves the other side alone where that app has no value. A per-field policy cannot be expressed there.

What if we cannot get last-modified data out?

The map still gets built from the configuration and still finds the cycles, which is genuinely useful. It just cannot prove the declared owner is the real one. Worth saying plainly rather than shipping a configuration diagram and calling it evidence.

How often does the map need redoing?

It is invalidated by events rather than by a calendar: any mapping change, any integration upgrade, any new tool granted write access. Upgrades that silently reset field mappings are real, so the trigger is named in the policy. It pairs with merge survivorship rules, a naming standard the classification rules read, and a change request and impact assessment for whatever field the redo touches.

Find out which system actually wins each field

Send your field exports, the integration and mapping settings, and anything showing who last modified a record, and get the map back with the counts.

Get the template