Statepatch synchronizes Statewire Documents across network boundaries.
Documents start with mount, followed by add, replace, or remove operations.
Mounting documents
mount
Starts syncing a document by sending its initial value.
{
"op": "mount",
"protocol": "harness-sdk",
"doc": 1,
"key": ["t1", "main", "42"],
"value": {"text": "Hello"}
}docgives the document a numeric ID for subsequent operations. Omitted means0; producers always omitdoc: 0.protocolnames a selected application protocol.main: trueidentifies that protocol’s main document. At most one is mounted per table.- Optional
keyis the document’s read address within its protocol. A main document may also have a key. valuecontains the document's initial data.
unmount
Stops syncing the document identified by doc over this transport.
{"op": "unmount", "doc": 1}Document lookup
- Document IDs belong to an attach.
- Protocols scope document keys. Message IDs unique within a thread use
[threadId, ns, messageId]. [".", ns, messageId]addresses a message before a thread ID exists. The client’s protocol key prefix resolves.when canonical identity becomes available.- Relative keys remain usable for local reads while unresolved. Shared storage uses resolved keys and an optional client-configured namespace.
- Protocol negotiation defines mounts, main documents, key resolution, and storage identity.
Mutating documents
Paths
Inside a document, a path lists the object keys and list indices leading to a value.
["messages", 0, "text"]points to the first message'stextfield.[]points to the whole document.- Object keys are strings; list indices are nonnegative whole numbers.
- Objects and lists along the path must already exist.
add (list)
Inserts a list item and shifts later items to the right.
- Previous state
- { "items": ["a","c"] }
- Operation
- { "op": "add", "path": ["items",1], "value": "b" }
- Final state
- { "items": ["a","b","c"] }
The final path index is the insertion position, from 0 to the list length: 0 inserts at the start; the length inserts at the end.
add (string)
Inserts text into a string.
- Previous state
- { "text": "Hello" }
- Operation
- { "op": "add", "path": ["text",5], "value": " world" }
- Final state
- { "text": "Hello world" }
- The final path index is the insertion position, counted in Unicode code points from
0to the string length. - The inserted
valuemust be a string.
replace
Sets the value at a path.
- Previous state
- { "count": 0 }
- Operation
- { "op": "replace", "path": ["count"], "value": 1 }
- Final state
- { "count": 1 }
- Object keys can be new. List items must already exist.
- Use
[]to replace the whole document.
remove
Deletes an existing object key or list item, shifting later list items to the left.
- Previous state
- { "items": ["a","b","c"] }
- Operation
- { "op": "remove", "path": ["items",1] }
- Final state
- { "items": ["a","c"] }
Operation format
A statepatch is an ordered array of statepatch operations. Each operation has an op and selects a document by its numeric doc ID, which defaults to 0.
op | doc* | path | key | value | meta* |
|---|---|---|---|---|---|
mount | ✓ | — | ✓ | ✓ | ✓ |
unmount | ✓ | — | — | — | — |
add (list) | ✓ | ✓ | — | ✓ | ✓ |
add (string) | ✓ | ✓ | — | ✓ | ✓ |
replace | ✓ | ✓ | — | ✓ | ✓ |
remove | ✓ | ✓ | — | — | — |
* Optional. All other checked fields are required.
Operations apply in order; each sees the previous operation's changes. Operations that break the path or operation rules are protocol errors.
Client handling
- Clients skip unknown operations and warn once per operation name.
Statepatch is inspired by JSON Patch, Immer patches, and SuperJSON.
Python validation
from statepatch import WireEncodingError exports a ValueError subclass for invalid wire values. Observable mutations raise it for encoding violations. Statewire preserves these library diagnostics while redacting unexpected handler exceptions.