River
Y CombinatorBacked by Y Combinator
FREE TEMPLATE

Reverse ETL Documentation Template

Three documents and three sheets that decide, field by field, what happens when your warehouse and a human editing the same CRM record disagree.

Free download  ·  No account needed

Conflict and Overwrite Rules

One row per field that could be edited on both sides

Filled in before a field goes live, not after a rep notices their note is gone. A field earns its policy from real edit history, not from how the sync happens to be configured today.

Owner Classification

Warehouse-only, Shared, or Destination-only, decided by pulling the destination's own edit or property history for that exact field over a real window, never assumed from memory.

Human Edits Observed

A count, not a yes or no. Zero real edits in the window is Warehouse-only. Any edits at all make it Shared, however few.

Overwrite Policy

One of three, chosen with a stated reason: only write when the destination field is empty, let the newer timestamp win, or exclude the field from the mapping entirely and pull it back into the warehouse one way instead.

Detection Mechanism

How the policy is actually enforced: which per-field timestamp or property-history feed it reads. A policy with no real mechanism behind it is a label, not a control.

Every practical result for reverse ETL documentation is a vendor's own product docs: Census, Hightouch, Fivetran, and the smaller platforms. Each covers the same three things, a source query, a destination object, and a field mapping with a sync mode. Hightouch's own HubSpot guide names the risk: its default field behavior, Always sync, writes the model's value on every run, including nulls, and can erase existing production data. The safer option sits on the same page, and Fivetran ships an equivalent under a different name. No vendor page inventories which fields need it.

So Conflict and Overwrite Rules is that inventory. Anything a human can also edit in the destination gets its real edit history pulled for sixty to ninety days, a count rather than a guess. That count decides one of three policies: write only when the destination field is empty, let the newer timestamp win, or remove the field from the mapping and pull it into the warehouse one way instead. A field nobody but the warehouse ever touches keeps the sync's default.

Northfield Systems, a fictional B2B SaaS company, syncs 28 fields into HubSpot's Company object hourly. Twenty-one are pure telemetry. The other seven are also edited by revenue operations, and all seven sat on the Always sync default: 96 human edits logged over 60 days, every one reverted by the next hourly run, 28 minutes later on average. Reclassifying the seven moved 62 of those 96 edits onto a policy that makes overwrite structurally impossible and the other 34 onto one where only a genuinely fresher value wins.

96 human edits reverted in 60 days, until every field got a real policy

The Conflict and Overwrite Rules sheet, and what changed once it replaced the sync's default.

Conflict and Overwrite Rules

Northfield Systems, a fictional B2B SaaS company. 28 fields sync hourly into HubSpot's Company object; these 7 are also edited by revenue operations.

FieldEdits, 60dOld policyNew policy
renewal_forecast_category22Always overwriteNewer wins by timestamp
champion_contact_name19Always overwriteOnly write to empty
renewal_risk_note17Always overwriteExcluded from mapping
primary_competitor14Always overwriteExcluded from mapping
next_renewal_action12Always overwriteNewer wins by timestamp
preferred_contact_method7Always overwriteOnly write to empty
deal_blocker_flag5Always overwriteOnly write to empty

Every one of these 7 fields was left on Hightouch's own stated default, Always sync, which writes the warehouse value every run regardless of what changed in HubSpot since. The field mapping looked identical to the 21 pure-telemetry fields on the same sync. Nothing about a healthy-looking sync run distinguished a safe field from a risky one.

renewal_forecast_category alone was edited 22 times in 60 days and reverted 22 times. The highest-edit field also has the most defensible case for letting a fresher value win, since both the computed forecast and a rep's override are legitimate; it is not a field to exclude, it is a field to compare by timestamp.

Warehouse-only fields, the other 21 on this sync, are not shown here. Zero real edits in a 60-day pull keeps them on the default with no further review.

Before / After

The same 96 edits, grouped by what happens to them under the old policy versus the new one.

GroupEditsShareOutcome going forward
Old policy: Always overwrite, all 7 fields96100%Reverted by the next hourly run, no exceptions
New: excluded from mapping3132.3%Cannot be overwritten; field removed from the outbound sync
New: only write to empty3132.3%Cannot be overwritten once a value exists
New: newer wins by timestamp3435.4%Overwritten only when the warehouse value is genuinely more recent

62 of the 96 edits, almost two-thirds, move to a policy where overwrite is structurally impossible rather than merely less likely. Excluding a field or writing it once are both permanent fixes; neither depends on the sync behaving correctly on any given run.

The remaining 34 do not become unconditionally safe, and the sheet does not pretend otherwise. A newer-wins policy can still overwrite a human edit, exactly once, when the warehouse genuinely recomputed something more current, which is a defensible outcome a same-field, all-runs revert never was.

Zero of the 96 were reviewed individually. The fix is seven policy decisions, not ninety-six.

What's in the pack

01

Sync Specification

How a sync is named and built, the source query rules, which sync modes are allowed, and how it defers to pipeline documentation for whether the source model itself is trustworthy.

02

Ownership Note

Who owns a sync, who owns classifying a field, and the escalation path when two teams disagree about whether a field is really edited by hand.

03

Failure Handling

Schema drift, rate limits, partial batch failures, what is recoverable when a field is found on the wrong policy, and what to re-check first after a model migration changes what a synced field means.

04

Field Mapping

One row per field per destination, source column to destination field, with the transform and the owner classification every policy decision is built from.

05

Sync Register

One row per sync job with its mode, match key, cadence and field count, cross-checked against Field Mapping so nothing drifts unnoticed between them.

06

Conflict and Overwrite Rules

Every shared field's real edit count, its assigned policy, and the detection mechanism the policy actually depends on, the sheet the rest of the pack exists to feed.

How to use it

  1. 1

    Open in River, or take it blank

    Claim the pack in River and hand it a live field mapping, or take the blank documents and sheets and fill them in yourself.

  2. 2

    Send the mapping and the history

    Your current field mapping for one sync, plus whatever edit or property history the destination exposes for the fields in question.

  3. 3

    Get every field classified

    River sorts each field into warehouse-only, shared or destination-only from the real edit counts, then proposes a policy for every shared one.

  4. 4

    Fix what's already live

    Correct any field currently sitting on a risky default before the next scheduled run, starting with whichever has the most recorded edits.

Frequently asked questions

Is this template free?

Yes, no account or card needed to download it. Edit with AI is the optional half, where River reads your field mapping and the destination's edit history and classifies every field itself. Every other pack sits in the template library.

What format are the downloaded files?

Three documents as Word files and three sheets as CSVs, zipped together. The sheets ship with Northfield Systems' illustrative rows in place, so the classification and the policy split are visible before you replace them with your own fields.

Our reverse ETL tool already has a null-handling setting. Why do we need this?

That setting is real and this pack uses it; it is also a switch you set once per field with nothing inventorying which fields need it set to something other than the default. This pack is the inventory: every field, its real edit history, and the policy that follows from it.

How do we know if a field is really edited by a human?

Pull the destination's own edit or property history for that exact field over sixty to ninety days and count it. Zero edits in the window is warehouse-only. Any edits at all make it shared, however few, and memory is a worse source than the count.

What if our CRM doesn't track per-field edit timestamps?

Then "newer wins by timestamp" is not available for that field, and the pack defaults it to "only write to empty" or excludes it instead. A policy that claims to compare timestamps nothing is actually recording is worse than having no policy at all.

Does this replace defining what the field actually means?

No. A field's definition, what health_score is supposed to represent and how it is computed, belongs in a data dictionary. This pack governs what happens once that already-defined field is pushed somewhere a human can also touch it directly.

Our warehouse and CRM data can't leave our network. Can we still use this?

Yes. A private AI workspace runs the pack inside your own tenancy, so field names, edit counts and destination credentials never cross a boundary your data governance has not approved. The classification and the register work exactly as described here.

Find out which synced fields are one sync away from overwriting a human

Start from the blank documents and sheets, or send River your field mapping and let it classify every field from real edit history.

Edit with AI