# 1.1.0 persistent state delivery > Version: 1.1.0. Release requirements; implementation and delivery are recorded below. > [Verification status](/Riff/1-1-0/status). ## Acceptance and durability Retain the existing reliable Binder Stop-and-Wait transport. Transport SESSION/SEQ identify delivery, not history age. ACK must distinguish ACCEPTED from SAVED. ACCEPTED means validated application to Indexer RAM and releases the control pipeline. Player retains the pending semantic operation. SAVED follows durable CURRENT publication and identifies root, writer, file scope, covered sequence and file generation. Discard only covered pending changes. Each logical file persists one compact WriteReceipt: content-derived 64-bit writer_id and its highest contiguous applied sequence. Sequences and profile slots are ordinals, not entity IDs. No per-event permanent journal is introduced. The current live Player is the only mutation producer. ## Idempotence Capture root/session/profile before enqueue. Apply expected sequences once; reject out-of-order future operations and reuse of a sequence with different payload. Return the original outcome for retries without changing RAM or deadlines. On Indexer restart, compare saved receipts and replay only unconfirmed effects from the surviving Player. START is one command carrying its profile checkpoint/qualification effect and history append. Its two file receipts are published together. A no-op is final only when its required result is already durable; otherwise its completion depends on the pending publication that supplies it. Assign identity and freeze payload before dispatch. Progress can coalesce before assignment only. Large queue payloads use bounded read-only descriptor transfer over Binder, not oversized strings or an unbounded Binder parcel. Apply backpressure without blocking audio/UI/ACK handlers or silently discarding accepted commands. A new Player incarnation closes the old writer and cannot replay its commands. A surviving Indexer drains previously accepted work before opening the new writer. A handshake alone does not publish history. Root relocation/reset fences stale messages independently of identifier equality. ## Typed command envelope A semantic operation that changes profile and installation together is one accepted transaction, including Settings/profile selection and queue activation/playback ownership. Do not rely on the 5-second debounce to make separately delivered commands atomic. Validate all patches before applying the group; reject the entire group on failure. A publication commits its dependent dirty files through one manifest. Each file keeps its own sequence, receipt and generation. START still couples its profile patch to the Indexer-owned history append. The existing channel stages one bounded read-only descriptor, keyed by raw XXH3 of the complete payload. USER_STATE carries that checksum; the descriptor contains the following transient envelope. It is not another durable user-state file or a second reliability layer. A result reports ACCEPTED or SAVED per patch, with actual scope, covered sequence and generations. Retain each effect until its required SAVED prefixes; replay a grouped envelope unchanged when only some notifications arrived. Use protocol_version 1 and non-null root_id/writer_id, including numeric zero as valid identity. The writes vector contains one through four distinct installation/profile scopes, in acceptance order. INSTALLATION uses slot 0, installation only and no start. PROFILE uses slot 1..3, profile only and optional Music START. Each sequence is positive and fits Long.MAX_VALUE. Direct history-file patches are prohibited. Bound the entire descriptor to 64 MiB and validate offsets, enums and required fields before allocation. Cross-process pointers or mutable shared buffers are not input. ```fbs include "../user_state/profile_state.fbs"; include "../user_state/installation_state.fbs"; namespace link.roadio.riff.state.fbs; enum UserStateWriteKind:ubyte { INSTALLATION, PROFILE } table UserStateWrite { kind:UserStateWriteKind; profile_slot:ubyte; sequence:ulong; profile:ProfileState; installation:InstallationState; start:MediaKey; } table UserStateCommand { protocol_version:uint = 1; root_id:ulong = null; writer_id:ulong = null; writes:[UserStateWrite] (required); } root_type UserStateCommand; file_identifier "UCMD"; ``` ## Failure boundary and UI If Indexer dies, a live Player replays pending work. If CURRENT committed but SAVED was lost, persisted receipts prevent a second effect. If Player dies, work already accepted by a live Indexer can still finish; changes held only in Player RAM are lost. Power loss can lose all unpublished work. This is an explicit RAM-outbox boundary, not a promise of a durable Player WAL. Immediate local visual feedback is permitted. Durable-success results, including committed dialogs, must not be fabricated from ACCEPTED. Keep accepted UI actions pending through the existing non-cancellable completion path; errors remain bounded and accessible. No UI waits synchronously on Binder, serialization or fsync. Existing source-attempt transport remains separately owned by the baseline IPC contract. This page extends durable user-state delivery; it does not reinterpret source failure telemetry. ## Root activation fence Relocation drains Player until SAVED, fences Indexer, and copies the complete root under the existing storage contract. The copied root is activated in Indexer before Player requests its new descriptors or opens a replica. This applies even with zero media grants or disabled catalog browsing. On a failed move, activate the actual bootstrap-selected root before reopening Player. Repeated fence requests are idempotent. Only the separately confirmed fresh-Internal reset may discard pending RAM; ordinary relocation cannot use that exception.