Delete reconciliation currently applies to OpenSearch and Elasticsearch
sinks. Redis uses a different rebuild contract: normal pause and resume
preserve the cursor, while an exclusively owned keyspace can be cleared by
finite routed targets and restored from a source snapshot. Shared Redis
keyspaces reject destructive drain and rebootstrap operations.
When it runs
On a drain → resume cycle, before the bootstrap re-emits documents. If rows were deleted during the drain window, the agent reconciles them away first, so the re-bootstrap starts from a clean index.How it works
The pass is before-bootstrap by design — it needs no engine internals and runs once per drain-resume:1
List source keys
Query the source for the current set of primary keys / element IDs
(streamed via a server-side cursor, so a 100k-row table never
materializes in memory at once).
2
Scroll the index
Page through every document in the target index using the scroll
API.
3
Diff + bulk-delete
Any document whose key isn’t in the source key-set is an orphan.
Bulk-delete them (1,000 per request).
Cost characteristics
The scan cost is proportional to the number of documents in the target index, not the number of orphans. The source-key set is held in memory for the duration of the pass, so measure both runtime and peak memory with production-like data before scheduling reconciliation for a large index. Run it during a lower-traffic window when the scan would compete with search traffic.Composite keys
Reconciliation handles both single-column and composite primary keys (Postgres) and element IDs (Neo4j) — no table is skipped for having a multi-column key. The live key set the source returns is folded into the same canonical form as the deterministic doc ID, so the diff works regardless of key arity:- a single column keys the set by the bare value
(
shop.orders:["uuid"]); - a composite key serializes every key column, in declared order, as
a JSON array (
shop.cart_items:["cart-42","prod-9"]).