Implement replay-safe browser synchronization
This commit is contained in:
parent
06a7ac56b7
commit
459ffa04c6
1 changed files with 2734 additions and 25 deletions
|
|
@ -13,13 +13,17 @@ path or media type.
|
|||
|
||||
## Idempotency
|
||||
|
||||
Every public mutation requires `Idempotency-Key`. The identity is caller
|
||||
Every public domain mutation requires `Idempotency-Key`. The identity is caller
|
||||
subject, operation, and key. The server canonicalizes the semantic request,
|
||||
including the authorization target, with RFC 8785 and stores its SHA-256
|
||||
fingerprint and complete response atomically with the mutation. The default
|
||||
retention is 24 hours and is never shorter than the advertised
|
||||
`Idempotency-Expires-At`.
|
||||
|
||||
Event-ticket issuance is an ephemeral authentication exchange rather than a
|
||||
domain mutation. Each retry independently mints a short-lived credential; it
|
||||
does not refine a `JobProtocol` effect or enter the public mutation ledger.
|
||||
|
||||
The same identity and fingerprint replays the original status, resource, and
|
||||
body after duplicate or ambiguous delivery. A different fingerprint returns
|
||||
`idempotency_conflict` and cannot affect either request. Naturally idempotent
|
||||
|
|
@ -118,7 +122,15 @@ An HTTP job or list snapshot carries `event_cursor` at its consistency
|
|||
watermark. The client connects to `/v1/events` with that cursor; there is no
|
||||
subscription frame. Server frames are ordered by increasing `sequence` for a
|
||||
connection and carry an opaque next cursor. Delivery is at least once, and
|
||||
clients deduplicate event IDs.
|
||||
clients deduplicate event IDs. Each connection starts at sequence one and
|
||||
increments it by one for every frame, including heartbeats and replayed event
|
||||
IDs; a client resnapshots when it observes a gap.
|
||||
|
||||
Browser clients first create a short-lived, single-use event ticket through an
|
||||
OIDC bearer-authenticated HTTP request. The server stores only its digest and
|
||||
binds it to the authenticated principal and exact allowed origin. Redemption
|
||||
atomically consumes it during the WebSocket handshake. Native clients may
|
||||
authenticate that handshake directly with the OIDC bearer header.
|
||||
|
||||
`job_changed` is an invalidation with an attempt-aware display hint, not a
|
||||
resource replacement or patch. A client compares `job_revision` with the last
|
||||
|
|
|
|||
Loading…
Reference in a new issue