Keyed List Reconciliation
Relevant source files
The following files were used as context for generating this wiki page:
Keyed List Reconciliation is a core feature of the keyfold library that enables intelligent merging of arrays based on unique item identities rather than array indices. While standard JSON Merge Patch (RFC 7396) treats arrays as opaque values to be replaced entirely, keyfold allows for granular updates, deletions, and insertions within lists by matching items via a configured identity field. This ensures that state trees remain consistent and structural sharing is preserved where possible.
Sources: README.md:1-20, AGENTS.md:40-44
Core Architecture and Data Flow
Reconciliation is handled primarily by the reconcile function, which is invoked when the merger encounters a path configured in the keyBy policy. The process involves indexing the delta, iterating through the base list to match identities, and then appending any new items found in the delta.
The Reconciliation Process
The following diagram illustrates the logical flow of reconciling a base list against a delta list:
The reconciliation process ensures that surviving items retain their original order from the base list, while new items are appended at the end in the order they appear in the delta.
Sources: src/reconcile.ts:16-65, AGENTS.md:40-44
Key Components and Logic
Identity Management
Identities must be stable, unique strings or non-NaN numbers. Matching is strict, meaning 1 and "1" are treated as distinct entities. If a base list contains duplicate identities, or if the delta contains duplicates, the system throws a KeyfoldMergeError.
Sources: src/reconcile.ts:109-138, README.md:53-57
Tombstones ($delete)
To remove an item from a keyed list, the delta item must contain the reserved $delete field set to true. A tombstone must only contain the identity field and the $delete field; providing additional patch fields within a tombstone results in an error.
Sources: src/reconcile.ts:140-156, test/reconcile.test.ts:175-188
Structural Sharing
A significant optimization in keyfold is structural sharing. If the reconciliation result is semantically identical to the base (e.g., the delta is empty or only contains no-op tombstones for absent items), the function returns the original base reference.
Sources: src/reconcile.ts:64-65, AGENTS.md:32-34
Configuration Options
Reconciliation behavior is dictated by the MergeOptions passed to createMerger.
| Option | Type | Description |
|---|---|---|
keyBy | Record<string, string> | Maps a dot-separated path to the identity field name (e.g., id, sku). |
replace | string[] | Paths to swap wholesale. Use path[] to replace items by identity instead of merging them. |
wireDeletes | boolean | If true, interprets the DELETE_TOKEN string as a field deletion within objects. |
Sources: src/types.ts:3-17, src/paths.ts:25-28
Path Syntax
Paths use dot-notation for object traversal and [] to indicate recursion into keyed list items.
items: Addresses the list itself.items[].components: Addresses thecomponentslist inside every item of theitemslist.
Sources: src/paths.ts:7-8, README.md:120-128
Implementation Details
Reconciliation Function Signature
export function reconcile(
base: readonly unknown[],
delta: readonly unknown[],
identityField: string,
itemPolicy: PolicyNode | undefined,
context: FoldContext,
path: string,
): readonly unknown[]
Sources: src/reconcile.ts:16-24
Constraints and Failure Safety
The implementation follows a "failure-safe" pattern: the delta is fully indexed and validated before any output array is created. This ensures that if an error occurs (like a duplicate ID), the base state remains completely untouched.
Sources: src/reconcile.ts:28, AGENTS.md:29-31
Conclusion
Keyed List Reconciliation provides a deterministic and immutable way to update complex nested lists. By combining identity-based matching with structural sharing, keyfold maintains high performance and predictable state updates, ensuring that partial deltas can be folded into state trees without the corruption risks associated with index-based merging.
Sources: AGENTS.md:35-36, README.md:144-152