> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twine.se/llms.txt
> Use this file to discover all available pages before exploring further.

# Diff Engine

> How Twine reconciles dated records with a target system and writes the minimal set of changes

When Twine sends data to a target system, it rarely wants to replace everything. The records already in the target usually overlap with what Twine wants to push, and most of them should stay exactly as they are. The **Diff Engine** is the component that works out the difference: it compares the records Twine wants the target to have against the records the target already has, and produces the minimal set of changes that makes the target match.

This reconciliation runs per **section** - one dated, multi-valued part of an entity, such as an employee's salaries, employment periods, or dimensions. Each section is reconciled independently and has its own behavior, configured under **Per-section sync behavior** in the [domain mapping](/platform/domain-mappings) configuration form.

How much is configurable depends entirely on the target system, and the range is wide:

* **No settings at all.** Many systems expose no Diff Engine configuration. Their reconciliation is fixed, or the integration only receives data and never has records to diff against.
* **A handful of sections.** A system might expose one or two dated sections, each with its own settings.
* **Many independent sections.** A system such as [FlexHRM](/integrations/hris-payroll/flex_hrm) breaks its data into a large number of separate dated sections, each configured on its own with no shared setting between them.

The set of sections, and whether any appear at all, is declared by the target system (see [System capabilities](#system-capabilities)). The settings described on this page apply to whichever sections a given system exposes.

<Note>
  Only date-tracked, list-valued data is reconciled this way. Single, undated values are always overwritten on each sync and are not subject to the settings on this page.
</Note>

## Source and target

The Diff Engine always works with two timelines for the same section:

* **Source** - the records Twine has computed locally and wants the target to end up with.
* **Target** - the records that currently exist in the remote system.

Each record carries a start date and an optional end date. A record with no end date is **open-ended** - still in effect with no scheduled end. The engine never changes a record's business fields; it only decides which records to write and adjusts their date boundaries so the two timelines line up.

For background on how Twine represents dated values, see [dated properties](/platform/data-model#dated-properties).

## The four outcomes

Reconciling the two timelines sorts every record into one of four outcomes:

| Outcome    | Meaning                                                                                               |
| ---------- | ----------------------------------------------------------------------------------------------------- |
| **Keep**   | A target record already matches the source. It is left untouched - no write.                          |
| **Create** | The source has a record the target is missing. It is written as a new record.                         |
| **Update** | A target record needs to change. It is rewritten in place, keeping its identity in the target system. |
| **Delete** | A target record should no longer exist. It is removed.                                                |

The goal is always the smallest set of writes that reconciles the two sides, so unchanged records never generate traffic to the target system.

## How records are compared

Whether a record is **kept** or **updated** comes down to comparing its values. The comparison looks at the record's business fields only - **the start and end dates are deliberately excluded**. Two consequences are worth knowing, because both can be surprising the first time they are seen:

* **An update can appear with no visible field change.** If a record's only difference is its dates - for example, an employment whose end date moved - its business fields still compare as equal, but the engine surfaces it as an `update` so the new date boundaries get written. The diff shows an update even though no field value changed.
* **Type-only numeric differences do not count.** A value of `100` and a value of `100.0` are treated as equal, so a difference that is purely integer-versus-decimal never registers as a change.

## Settings

The defaults are sensible for most setups. The settings below let you tune how a section is reconciled when the default behavior is not what a given target system needs. Each applies per section.

### Mode

How the engine reacts when a configured rule blocks an operation.

* **Strict** - halt the whole sync as soon as any rule is violated. Nothing is written.
* **Safe** - drop the blocked operation, record it as a warning, and continue with the rest of the diff.

### Fragmentation strategy

How incoming source records are fitted around the boundaries of records that already exist in the target.

* **Slice source** (non-destructive, default) - fits incoming records around the target's existing boundaries, splitting the source where needed so surrounding target structure is left undisturbed.
* **Overwrite target** (destructive) - enforces the source's boundaries and deletes any target records that get in the way. This yields a cleaner timeline with fewer records, but the records that are rewritten get new identities in the target system. It requires that deletes are allowed.
* **Extend target terminus** - behaves like slice source everywhere except at the end of the timeline. When an ongoing source record continues immediately past where a surviving target record ends, that existing record is stretched to cover the continuation instead of a brand-new record being created. This keeps a continuing record under its existing identity rather than minting a duplicate. A period the source has deliberately closed is still closed - only a genuine continuation is absorbed.

### Unmatched target records

What to do with a target record covering a period the source says nothing about.

* **Preserve** - leave the target record untouched.
* **Delete** - remove it.

Use **preserve** unless the source is meant to be the absolute source of truth for the section. **Delete** is appropriate only for true mirroring, where anything not present in the source should not exist in the target.

### Mutation scope

A time lock that restricts how far back in history the engine may change existing records.

* **All records** - changes are allowed anywhere in the timeline.
* **Latest only** - every record before the most recent one is locked; only the latest record may be amended.
* **Started on/after date** - records that start before a fixed cutoff date are locked. The cutoff is set alongside this option.

Mutation scope only restricts changes to existing records. It does not apply when a section allows inserts only, since there is nothing to lock.

### Allowed operations

Which of **Insert**, **Update**, and **Delete** the engine may perform for the section. Operations the target system cannot perform are filtered out automatically (see [System capabilities](#system-capabilities)). When an operation is disallowed, the engine strips it rather than writing it - and a change that only adjusts a record's date boundaries is reverted to leaving the record at its original dates, so it does not vanish.

### Require at least one record

Blocks any diff that would leave the section with zero records. This guards against a sync that would, for example, delete an employee's only active employment. When a target system requires a section to always hold at least one record, this option is locked on.

### Suppress historical creates

Drops source records whose start date falls before the target's most recent record. This stops the engine from back-filling old periods that predate what the target already knows about - useful when the source occasionally surfaces historical data that should not be replicated.

## System capabilities

Not every target system can do everything. Each integration declares which sections it reconciles - from none to many - and what it supports for each one. Those declarations shape the form and constrain the settings above:

* Which sections appear (and in what order) is set by the system. A system that declares no diffable sections shows no Diff Engine settings at all.
* Operations the system cannot perform are removed from **Allowed operations**, so they can never be selected.
* When a system requires a section to always keep at least one record, **Require at least one record** is forced on and locked.
* Some sections accept only a single record. For those, many local records are collapsed into one before being written.

Because capabilities are enforced at configuration time, the form only ever offers choices the target system can actually carry out.

## Strategy presets

Newer integrations expose the granular per-section settings described above. Other integrations expose a single named **strategy** per section instead - a preset that bundles those settings into one choice. When a section has no explicit configuration, a default preset applies.

| Preset                         | Behavior                                                                                                                               |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| **Overwrite**                  | Absolute mirror. The target is made to match the source exactly, deleting records the source no longer has. Destructive.               |
| **Append Differences**         | Append-only. New source records are added; existing target records are never changed or removed.                                       |
| **Append and Amend Latest**    | History is protected. New records are appended and only the most recent record may be amended.                                         |
| **Optimistic Append or Amend** | The default fallback. Appends and amends as needed across the timeline, but does not back-fill records older than the target's latest. |

## Conflicts: strict versus safe

When a rule blocks an operation, what happens next depends on the section's [mode](#mode):

* In **Safe** mode the blocked operation is dropped and recorded as a warning, and the rest of the diff is written. The sync succeeds with a record of what was skipped.
* In **Strict** mode any single violation aborts the entire sync. Nothing is written until the conflict is resolved.

One refinement applies in both modes: when a change that only adjusts a record's date boundaries is blocked, the record is kept at its original dates rather than dropped. The record stays represented in the target unless a genuinely changed record overlaps and replaces it.

## Worked example: a future-dated termination

An employee's employment is being replicated to a payroll system. Locally the employment has been closed with an end date of 2026-07-31 - a termination. In the payroll system the same employment is still open, with no end date. Every other field is identical.

The section is configured with **Safe** mode, **Extend target terminus**, **Preserve** unmatched records, **Latest only** mutation scope, and **Insert** and **Update** allowed (no deletes).

```
Source (Twine):    2022-10-04 ───────────────● 2026-07-31   (closed)
Target (payroll):  2022-10-04 ──────────────────────────▶   (still open)
```

The result is a single **update** that sets the employment's end date to 2026-07-31. The termination is pushed to payroll, no duplicate employment record is created, and there is no redundant no-op update.

This is the careful outcome. Because the source closed the period, the still-open tail in the target is recognized as a deliberately ended period, not an ongoing record to keep alive. Extend target terminus stretches a target record only when the source genuinely continues past it; it never re-opens a period the source has closed.

<Card title="Domain Mappings" icon="arrow-right-arrow-left" href="/platform/domain-mappings">
  Where per-section sync behavior is configured, alongside conditions, sync triggers, and pre-processors.
</Card>
