# Conditional server transactions Available in the development checkout. The frozen 0.1.0 alpha binaries predate these additive protocol v1 commands. Upgrade the client and server before using them. Read a shiny with `get_versioned` in its selected den. The server returns its document (null when absent) and the instance generation while holding the database mutex. To coordinate changes across multiple reads, use the same generation for all inputs. If generations differ, reread the inputs before computing a write set. Submit the write set in one authenticated request. The server compares the required unsigned 64-bit `expected_generation` with its current generation under the same mutex that protects publication. Each change supplies its warren, den and ID explicitly. Individual puts replace or insert a complete object. Deletes remove the given ID and allow an already-absent ID. Neither operation modifies session navigation. ```json {"version":1,"command":{"op":"get_versioned","id":"c-1"}} ``` For a read that returned generation 42, a conditional edit and a durable application request marker can be sent together: ```json {"version":1,"command":{"op":"transaction","expected_generation":42,"changes":[{"op":"put","warren":"crm","den":"contacts","id":"c-1","document":{"name":"Jo","stage":"qualified"}},{"op":"put","warren":"crm","den":"requests","id":"req-17","document":{"contact":"c-1","action":"qualify"}}]}} ``` Success returns `{"generation":43,"changed_count":2}` in the response data after a single core commit. The count is the number of submitted changes, including a delete of an absent ID. A mismatch returns `generation_conflict` without applying any writes. The connection stays usable. Read again and recompute the change from current data. Any intervening instance mutation can cause a conflict, even a write to an unrelated den. A request accepts 1–128 distinct namespaced IDs. All keys and encoded values together must fit the embedded 1 MiB batch budget. The server's frame limit and each document's configured size limit apply as well. Warren and den names follow the navigation component rules. Repeated IDs and invalid document objects reject the whole write set. A malformed wire envelope returns `bad_frame` and closes the connection. A storage error after a commit begins can require a server restart and reconciliation. A missing reply gives the client an unknown outcome. Reconnect and look up a unique application request marker that was written in the same transaction. Keep that marker immutable for the reconciliation window. A generation alone cannot identify which request committed. After a restore or reconnection to a different database, discard saved generations and reread application state. The shell commands are `get-versioned ` and `transaction `. A script can use the Python client's `get_versioned` and `transaction` methods or the Rust client's `Den::get_versioned` and `Client::transaction`. Clients transmit each transaction once. Scripts using `ratdb batch` still commit separate input lines independently. ## Verification ```sh cargo test --locked -p ratdb-server --test server transactions:: cargo test --locked -p ratdb-cli --test workflows crm_batch_restart_and_reconnect cargo build --locked --release -p ratdb-cli python -B scripts/python_client_test.py target/release/ratdb ``` On Windows use the installed Windows GNU Rust toolchain and the .exe path. The three real TCP server tests race two authenticated clients at the same generation, check all-or-nothing rejection for seven invalid write sets and a malformed frame, and disconnect after sending a complete transaction without reading the reply. The restart test reconciles the marker and deletion from a fresh session. File-level crash behavior uses the established embedded batch publication path. On November 7, 2026, Windows x86-64 GNU passed all three transaction TCP tests, the CLI workflow with versioned reads and transactions, and five Python client integration tests against the optimized CLI. The server and CLI test suites passed 22 tests in total and strict all-targets Clippy passed for both crates.