Lease context is part of the 2026-09-30 Statewire wire contract. The attach results cursor and verdict gap-fill are part of 2026-11-01.
Statewire exchanges JSON messages: clients send frames; servers send packets. Statewire Transport carries these messages over a connection.
Value encoding
Values use Statewire Document encoding. Each meta array describes dates inside the field carrying the data:
- State operations and context entries:
value. - Command statements:
params, starting with the argument index. - Command answers and
fin:payload.
Frames (client → server)
A frame is a client message carrying lease context, command statements, or both.
| Field | Meaning | Usage |
|---|---|---|
ctx | Array of protocol-scoped context replacements | Optional |
cmd | Array of command statements | Optional |
- A frame contains at least one nonempty array. A supplied empty array, an empty frame, or any key other than
ctxandcmdis a protocol violation. Transport headers on an initial attach and WebSocket heartbeats retain their transport rules.
Lease context: ctx
Each selected protocol has one client-owned context object on each attach, independently of its command lane's record.
{
"ctx": [{
"protocol": "acme-chat",
"value": {"locale": "en", "updatedAt": "2026-09-29T12:00:00.000Z"},
"meta": [{"path": ["updatedAt"], "type": "date"}]
}],
"cmd": [{"protocol": "acme-chat", "seq": 1, "method": "example", "params": []}]
}| Field | Meaning | Usage |
|---|---|---|
protocol | Selected application protocol, including a selected subprotocol | Required string |
value | Full context object in Statewire Document encoding | Required |
meta | Date metadata relative to this entry's value | Optional |
- Decode each
valueand optionalmetawith the Statewire Document codec. The decoded root is an object. Each protocol owns its context schema and validates its value. - Each protocol appears at most once in
ctx. A malformed entry, duplicate target, unselected protocol, invalid metadata, invalid context value, or oversized entry is a protocol violation. Validate the whole frame and every context candidate before changing context or admitting commands. - Context starts as
{}. Each entry replaces only its target protocol's object. Omitted protocols stay unchanged;value: {}clears that protocol's context fields. - Install the frame's context replacements together before comparing command watermarks or admitting commands. Each newly admitted command captures an immutable decoded context snapshot from its target protocol on its admitting attach. Repeated commands retain their original admission and outcome.
- Hosts expose context to that protocol's command handlers and a context-change hook. Context changes can update the attach's document view even in a context-only frame. Application authorization uses the admitting attach's auth.
- Context belongs to the attach, rather than the durable client record. Concurrent attaches sharing a client id have independent context. Already admitted work retains its captured context when the attach ends. Resumed execution uses its original captured context; if that snapshot cannot be recovered, fail the command rather than using another attach's context.
- Within an attach, hosts install context in frame arrival order. The last received value wins. Context entries carry
protocol,value, and optionalmeta; they have no sequence or revision field. - Clients retain each protocol's latest value and serialize its updates. On every new attach, including a fresh hello on a preserved socket, send the latest full values before submitting commands. Context restoration is independent of the connected flag.
- Context replacements consume no command sequence numbers, admission watermarks, command verdicts, durable replay entries, or in-flight command capacity.
- Command admission refusal leaves installed context intact. The refusal's
synapplies only to commands. A context-only frame completes after its context is installed; a WebSocket context-only frame has no command answer. - Context entries carry full replacements. Each context update carries the full object.
Lanes
A statement is one command request. A lane is the ordered sequence of statements of one selected protocol. Every selected protocol owns one lane; the hello lists them in syn.protocols[] as {name, version, seq, record?}.
| Lane | record | Numbering | Answers | Persistence |
|---|---|---|---|---|
| Durable | Absent | 1, 2, 3, …, continuing across attaches | Every attach of the client id | Client record |
| Ephemeral | "ephemeral" | Restarts at 1 on every attach; the hello reports 0 | The admitting attach only | None |
seqis minted in the statement's lane when the statement is queued.- Statements in one frame apply in array order across lanes. Across frames, arrival order. Replay after reconnect preserves order within a lane only.
- Within a frame, each lane's statements carry consecutive positive integer sequence numbers. Invalid numbers or a break in a lane are protocol violations.
- Unanswered ephemeral-lane statements are lost when their attach ends.
Command statements
A command statement calls an application command with positional arguments.
{"seq": 1, "protocol": "default", "method": "increment", "params": [1]}| Field | Meaning | Usage |
|---|---|---|
seq | Sequence number in the protocol's lane | Required |
protocol | Selected protocol name; subprotocols use their full <parent>/<child> name | Required string |
method | Command name | Required string |
params | Positional arguments | Required array; use [] for zero arguments |
meta | Date metadata for params | Optional |
- A missing
protocol,method, orparams, or a non-stringprotocolormethod, is amalformed statementviolation. - Invalid arguments or command metadata produce a
rejectedanswer withcode: "invalid-params". The command consumes its sequence number; other commands in the admitted frame can run.
Frame limits
| Limit | Maximum | If exceeded |
|---|---|---|
Statements per frame, across lanes (MAX_COMMANDS_PER_FRAME) | 256 | Protocol violation; bundled clients split larger backlogs |
| Context entries per frame | At most one per selected protocol | Protocol violation |
Encoded context entry, including value and meta | 64 KiB of UTF-8 | Protocol violation |
Encoded ephemeral document value (MAX_EPHEMERAL_DOCUMENT_BYTES) | 64 KiB | rejected with code: "oversized-document" |
| Encoded frame | 8 MiB of UTF-8 | Transport size error |
Packets
A packet is an object sent by the server.
| Field | Meaning | Usage |
|---|---|---|
syn | Connection facts or admission watermarks | Initial snapshot, refusal, watermark refresh, or identity confirmation |
ops | Statepatch array updating application state | Initial snapshot or state changes |
cmd | Array of command answers | Results, progress, or admission acknowledgments |
next | Hold answers until the next ops array | Optional true on a command-answer packet |
idle | Whether the instance has finished its work | Standalone or alongside ops |
fin | Connection ending | Final packet |
- Each attach receives its view of the selected protocols' documents. Command answers use that attach's selected contract.
- Clients ignore results for commands they do not track. Cumulative
duracknowledgments still advance their lane's watermark. - A packet may combine state changes and answers. Apply
opsfirst, thencmdentries in array order, and publish the changes together. - Clients ignore unknown packet keys.
Initial snapshot: syn + ops
A connection begins with a hello packet containing connection facts, the attach's document view, and answers to the attach request's ephemeral-lane statements.
{"syn": {"version": "2026-09-30", "protocols": [
{"name": "harness-sdk", "version": "2026-09-13", "seq": 41},
{"name": "harness-sdk/interest", "version": "2026-09-13", "record": "ephemeral", "seq": 0}],
"idle": true, "id": "..."}, "ops": [ ...mount ops for the attach's view... ], "cmd": [ ...answers to ephemeral attach statements... ]}A watermark is the highest sequence number accepted for processing in a lane. An admitted command may still be running.
syn field | Meaning | Default |
|---|---|---|
version | Selected Statewire date | Required |
protocols | Selected lanes, listed below | Required |
idle | Whether the instance is idle | false |
id | Instance identity | Absent |
syn.protocols[] field | Meaning | Default |
|---|---|---|
name | Selected protocol name | Required |
version | Selected protocol version | Required |
seq | Lane watermark; 0 on an ephemeral lane | Required |
record | "ephemeral" marks a lane that ends with the attach | Absent |
opsmounts the attach's whole document view and replaces the client's document table on reconnect. An empty view usesops: [].cmdcarries the answers to the ephemeral-lane statements of the attach request.- Validate negotiation fields before applying the snapshot.
- When every selected protocol is ephemeral, the client reports unanswered commands as lost when the connection ends and uses a fresh client id on the next connection.
- A durable host may report a lower durable-lane
seqbefore loading its retained admission record. Recovery uses refusal watermarks to resolve that case. - A server may end a connection immediately with
finas its first and only packet.
State changes: ops
ops applies a Statepatch to the client's document table. An accompanying applied answer marks the command's effects in that state.
{
"ops": [{"op": "replace", "path": ["count"], "value": 1}],
"cmd": [{"protocol": "default", "seq": 1, "type": "applied"}]
}The client observes count: 1 before processing command default 1's applied answer.
Command answers: cmd
Each answer names the command's protocol and seq and reports admission, progress, or a result.
{"cmd": [{"protocol": "harness-sdk", "seq": 3, "type": "result", "payload": 1}]}| Field | Meaning | Usage |
|---|---|---|
protocol | The command's lane | Required |
seq | Command sequence number in that lane | Required |
type | Progress or terminal verdict, listed below | Omitted on an admission-only acknowledgment |
payload | Return value or application rejection data | Optional |
meta | Date metadata for payload | Optional |
code | Machine-readable rejection code | Optional |
message | Error or rejection text | Optional |
dur | Retained admission through this sequence number | Optional true; durable lanes only |
applied is an intermediate answer. The other types are terminal verdicts: they settle the command.
type | Meaning |
|---|---|
applied | The handler marked its effects as applied. Remove the optimistic update; the command may continue running. |
result | The command completed successfully. payload holds its return value, when present. |
rejected | The method or arguments were rejected, or the handler explicitly rejected the command. |
failed | The handler threw. message is the command failed for unexpected exceptions; side effects may already exist. Explicit rejections and typed wire-encoding diagnostics retain their authored messages. |
crashed | The host witnessed handler death, such as cancellation during shutdown or eviction. |
expired | The command was admitted, but its stored verdict is unavailable. |
- The handler chooses when to emit
applied. Each admitted command has an optionalappliedtransition and one terminal verdict. Repeated submissions can re-emit answers. - Built-in rejections use
code: "unknown-command"orcode: "invalid-params". The synced document pair usesno-document,oversized-document, andinvalid-patch. Handler rejections carrymessageand optionalpayload, withcodeomitted. - Durable-lane answers fan out to every attach of the client id and persist in the client record. Ephemeral-lane answers return on the admitting attach only.
crashedrequires the host to observe the failure. After server recovery, a repeated command whose verdict is unavailable receivesexpired.
Retained admission: dur
dur: true releases commands through seq in the named lane from the client's resend queue. Their results may still be pending.
{"cmd": [{"protocol": "harness-sdk", "seq": 7, "dur": true}]}- The acknowledgment is cumulative within its lane: this example covers
harness-sdkcommands1through7. - A memory host acknowledges at admission, for the client record's lifetime. A durable host acknowledges when the admission's durable receipt completes.
durmay appear alone or on an answer, before or afterappliedor a terminal verdict.- Ephemeral lanes carry no
dur.
Deferred answers: next
next: true holds a packet's answers until this connection receives its next ops array.
{"cmd": [{"protocol": "default", "seq": 1, "type": "applied"}], "next": true}- Apply the next
ops, then the held answers, then any answers accompanying those ops. - With
nextomitted, process answers in their own packet.nextis invalid besideopsorfin. - A
finor transport close releases held answers before handling the close. Anappliedanswer still leaves the result pending.
Work status: idle
idle: true means the instance has finished its in-flight handlers, tracked tasks, and scheduled work.
{"idle": true}- The initial value is
syn.idle, defaultfalse. Later packets omittingidleleave it unchanged. - New client input may start more work. A one-shot client may close when idle.
- A host configured to finish on idle ends its connections with
finreasonidle.
Connection ending: fin
fin ends the connection and tells the client how to proceed.
{"fin": {"reason": "gone", "message": "Instance deleted"}}| Field | Meaning | Usage |
|---|---|---|
reason | Why the connection is ending, listed below | Required |
message | Explanatory text | Optional |
status | HTTP status, when applicable | Optional |
code | Machine-readable detail about the cause | Optional |
retry | Minimum reconnect delay in milliseconds for retryable finishes | Optional |
payload | Application data | Optional |
meta | Date metadata for payload | Optional |
reason | Meaning | Client action | onError |
|---|---|---|---|
reconnect | Expected disconnect; reconnect to continue | Reconnect with exponential backoff and jitter | No |
error | Unexpected, potentially recoverable failure | Reconnect with exponential backoff and jitter | Yes |
protocol-error | Invalid protocol data or an unsupported protocol version | Stop | Yes |
unauthorized | Credentials missing, invalid, or expired | Refresh credentials and reconnect once; stop after a second consecutive denial | If recovery fails |
forbidden | Access denied | Stop | Yes |
gone | The instance no longer exists | Stop | No |
idle | The instance finished its work | Reattach when needed | No |
code describes the specific cause. For reconnect:
code | Meaning |
|---|---|
evicted | The instance left this host |
overloaded | The host lacks capacity |
lease-expired | The attach reached its maximum authorization lifetime; reconnect and authorize again |
client-fell-behind | The host's outgoing queue for the client filled; reconnect for a fresh snapshot |
replaced | A later attach of the same attacher retired this one |
reauthorize | The host ended this attach so it authorizes again, typically after a role change |
For error:
code | Meaning |
|---|---|
filter-failed | The host's read filter for this attach failed |
compatibility-failed | The host could not project its state to this attach's selected versions |
identity-unencodable | The host could not store the attach's authorization result as the client id's durable admission identity |
{"fin": {"reason": "reconnect", "code": "overloaded", "retry": 5000}}- Recovery and
onErrorbehavior followreason; clients ignore unknowncodevalues. gone,forbidden,protocol-error, and a second consecutiveunauthorizedfail unanswered commands. Other reasons keep durable-lane commands pending for reconnection; ephemeral-lane commands are lost.- Command failures are reported separately from connection finishes.
- Every automatic reconnect after
finwaitsmax(client backoff, min(fin.retry ?? 0, client backoff ceiling))milliseconds from receipt offin. - Unknown reasons follow the
errorpath. A transport close withoutfinis a transport fault; reconnect. - Transport-specific failures and statuses are listed in Statewire Transport.
Admission
Admission accepts a frame's new statements for processing. All command lanes in a frame are admitted together; commands have individual outcomes afterward. Valid context replacements are installed before command admission and remain installed if new commands are refused.
Comparing with the watermark
In each lane, statements at or below its watermark are repeats. The first new statement must be watermark + 1.
Under 2026-09-30, for a harness-sdk watermark of 7:
Frame's harness-sdk sequence numbers | Outcome |
|---|---|
6, 7 | Repeat both; re-emit available answers |
8 | Admit command 8 |
6, 7, 8, 9 | Repeat 6 and 7; admit 8 and 9 |
9 | Refuse the new statements: command 8 is missing |
8, 10 | Protocol violation: the lane is not consecutive within the frame |
- Under
2026-11-01, the client gets its answers from the results cursor and sends a sequence number only while it is above the hello watermark. Another attach of the same client id can still land it first, such as a closed tab's frame arriving late. The host answers that repeat as under2026-09-30. Hosts before statewire 0.27.5 and statewire Python 0.23.4 end the attach as a protocol violation instead. - Under
2026-09-30, a gap in a durable lane refuses all new statements in the frame with the per-lane watermarks. Answers to repeats may still be re-emitted. Under2026-11-01, the gap refusal is unchanged. - Durable hosts load the retained durable-lane watermarks before comparing sequence numbers.
Attach statements
The attach request (POST /stream body or the WebSocket initial message) may carry a frame.
- Context is validated under the selected contracts and installed before the snapshot and any initial command admission.
- Ephemeral-lane statements are admitted before the snapshot is built: their documents ride the hello
opsand their answers ride the hellocmd. - Durable-lane statements run after the hello.
- The first ephemeral-lane statement of an attach carries
seq: 1; any other first sequence number is a protocol violation.
Replacing an attach
Under 2026-11-02, every attach of one client connection carries the same Statewire-Attacher token, minted by the client (WebSocket: in the first frame's headers). Two tabs sharing a client id carry different tokens. A client id with one holder at a time (session storage that is not shared) may keep its token across connections: then a reloaded page's attach replaces the previous page's.
- Before an attach's hello reads watermarks, the host retires the client id's earlier attaches with the same attacher. It does this after the principal checks, and a replaced attach does not count against the subscriber limit.
- Admissions in progress under a retired attach finish first. No frame is admitted under it again:
POST /framesanswers423, and its stream ends withfinreconnect/replaced. - So no frame sent on a replaced attach, including one whose hello never reached the client, lands after the new hello.
- Under earlier versions the header is ignored.
Results cursor: res
Under 2026-11-01, the attach frame may carry res: per durable lane, the sequence number through which the client holds every answer.
{"res": [{"protocol": "harness-sdk", "seq": 41}]}| Field | Meaning | Requirement |
|---|---|---|
protocol | Selected durable lane | Required, unique within res |
seq | Cursor; the client holds answers through it | Required nonnegative integer |
For each sequence number above the cursor and at or below the lane watermark, the hello cmd carries:
| Command | Answer |
|---|---|
| Settled, verdict retained | The verdict |
Running, after applied | applied |
Running, before applied | Nothing; its answers ride the stream |
| Settled, verdict unavailable | expired |
resis valid only on the attach request. On aPOST /framesbody, or under2026-09-30, it is a protocol violation.- Ephemeral lanes are skipped.
- Retained verdicts and
appliedanswers above the cursor are always sent.expiredcovers at most 4096 sequence numbers past the cursor per lane. - A frame carrying only
resis a valid attach frame.
Capacity
| Limit | Maximum |
|---|---|
| Admitted durable-lane commands per client that have not fully released, across lanes | 256 |
| Admitted commands across the host | maxInflightCommands / max_inflight_commands, default 1024 |
A frame exceeding either limit is refused with retry: 1000.
Refusals: syn
A refusal reports the exact admission watermarks and leaves the connection open. The frame's new statements remain unadmitted.
{"syn": {"protocols": [{"name": "harness-sdk", "seq": 41}], "retry": 1000}}retry | Meaning | Client action |
|---|---|---|
| Present | Temporary pushback | Wait this many milliseconds, then resend |
| Absent | Sequence gap | Reconcile with the watermarks and resend from each lane's next sequence |
protocols[]entries are{name, seq}: one per lane. Statements through those watermarks have been admitted; their answers arrive on the stream.retryis a nonnegative integer in milliseconds. Hosts may use it for capacity pressure or other temporary conditions. Clients cap the wait at their backoff ceiling.- Under
2026-11-01, a refusal can reach the client after frames it sent since were admitted. For durable lanes the client resends nothing from a refusal: it waits outretry, if present, and the answers to its attempted ephemeral-lane statements, then reattaches, and the hello decides. - Refusal delivery over HTTP and WebSocket follows Statewire Transport.
Watermark refresh: syn
A mid-stream syn without retry reports lanes whose watermark moved.
{"syn": {"protocols": [{"name": "harness-sdk", "seq": 41}]}}idlemay ride a mid-streamsyn.
Answers to repeated commands
Under 2026-09-30, within a retained client record, repeated sequence numbers in a lane refer to the same command execution.
| Original command | Answer to the repeat |
|---|---|
Running, before applied | Wait for its answers |
Running, after applied | Re-emit applied |
| Settled, verdict retained | Re-emit the verdict |
| Admitted, verdict unavailable | Emit expired |
- Verdicts are retained in memory for 30 seconds, up to 256 per client, with the newest kept. Durable hosts retain admission across restarts.
- To execute a command again after
rejectedorfailed, assign a new sequence number.
Reconnecting
Keep the client id and each durable lane's sequence clock across page loads, except when every selected protocol is ephemeral.
Under 2026-11-01:
- Reconnect with the latest retained context values and a results cursor per durable lane with unanswered commands: the sequence number below the oldest one.
- For each durable lane, compare unanswered commands with the hello watermark. Commands at or below it were admitted: their answers ride the hello. Commands the attach carried from
watermark + 1on run after the hello: they count as sent. Other commands above it never arrived: assign them new sequence numbers after those before sending them. - A command above the watermark that the client saw admitted, or a first unanswered command above
watermark + 1, proves the record that admitted it is gone: report the lane's commands as lost and restart its clock at the watermark.
Under 2026-09-30:
- Reconnect with the latest retained context values and receive a fresh snapshot. On a fresh hello replacing an attachment on an existing socket, restore context before sending commands.
- Resend pending durable-lane statements with their original sequence numbers, consecutively within each lane. Ephemeral lanes start again at
1. - On a refusal with
retry, wait before resending. On a gap refusal, compare each lane's first unposted command with its next expected sequence, using the higher of the refusal'sseqfor that lane and anyduracknowledged for it on this connection. - If a command skips a prefix the client has already discarded, report held commands in that lane as lost and restart the lane's clock at the refusal's watermark.
For a refusal reporting {"name": "harness-sdk", "seq": 5}, with no higher dur acknowledged:
Client's pending harness-sdk commands | Recovery |
|---|---|
6, 7, 8, 9 | Resend from 6 |
9, with 6–8 already discarded | Report held commands as lost; the next command uses 6 |
- A lower durable-lane watermark in the hello alone leaves pending commands under their original sequence numbers.
Reserved behavior
- Method names beginning with
statewire/are reserved for protocol commands. statewire/commandsis mandatory within each protocol. Call it with the targetprotocolandparams: []; its result is that selected contract's sorted command-name array, including itself.- The
_instance-id segment is reserved for attaching before an instance exists. Its identity confirmation is{"syn": {"id": "..."}}; placeholder attaches are currently stubbed in the hosts.
Client handling
- Mid-stream
syn.version, mid-streamsyn.protocols[].versionorsyn.protocols[].record, andnextbesideopsare protocol errors. - Clients skip unknown metadata types from the server. Hosts reject unknown command metadata types as
invalid-params; invalid context metadata is a frame violation. - Hosts may use custom admission pushback in addition to capacity limits.