Problem
Several user-facing commands still span multiple writes even though callers experience them as one operation:
CreateRoom atomically publishes the room and default permission facts, then performs group placement through a separate best-effort MoveRoomToGroup. It can return a room whose response carries group_id while the durable group layout never acquired that room.
RoomCommandModel.UpdateRoom writes name/description and universal through two separate commits. The first can succeed while the second fails.
- Posting a thread reply with
also_send_to_channel commits the canonical reply first, then appends its channel echo separately and logs failure while returning success.
These partial-success states are durable. A request retry is not currently guaranteed to repair them and may create additional facts.
Thread creation, message body/post facts, default room permissions, and video-processing start facts already demonstrate that related EVT facts can be committed in one atomic batch.
Goal
Define the transaction boundary of each compound command. Facts required for the command’s promised result should commit atomically under the relevant OCC guards. Work that is intentionally asynchronous should have an explicit durable trigger, recovery policy, and observable status.
Acceptance criteria
- Decide and document the promised outcome for room creation, multi-field room updates, and thread-reply channel echoes.
- Room creation cannot report successful placement in a group unless room creation, required defaults, and group membership have committed consistently.
- Updating metadata plus
universal cannot leave only a caller-invisible prefix of the requested patch committed.
- A successful “also send to channel” command cannot permanently omit the requested echo without exposing an explicit pending/failure result and durable recovery path.
- Every atomic batch carries OCC guards for all invariants it spans and reruns the complete decision after conflicts.
- Projection waits cover every read model needed by the returned resource and subsequent live invalidation.
- Multi-replica race tests and failure injection cover every boundary between the component writes.
- Rolling-deploy and rollback behavior is documented before changing persisted write patterns.
- Architecture inventory and relevant FDRs are updated; split implementation work into focused child issues if one PR would be too broad.
Non-goals
Problem
Several user-facing commands still span multiple writes even though callers experience them as one operation:
CreateRoomatomically publishes the room and default permission facts, then performs group placement through a separate best-effortMoveRoomToGroup. It can return a room whose response carriesgroup_idwhile the durable group layout never acquired that room.RoomCommandModel.UpdateRoomwrites name/description anduniversalthrough two separate commits. The first can succeed while the second fails.also_send_to_channelcommits the canonical reply first, then appends its channel echo separately and logs failure while returning success.These partial-success states are durable. A request retry is not currently guaranteed to repair them and may create additional facts.
Thread creation, message body/post facts, default room permissions, and video-processing start facts already demonstrate that related EVT facts can be committed in one atomic batch.
Goal
Define the transaction boundary of each compound command. Facts required for the command’s promised result should commit atomically under the relevant OCC guards. Work that is intentionally asynchronous should have an explicit durable trigger, recovery policy, and observable status.
Acceptance criteria
universalcannot leave only a caller-invisible prefix of the requested patch committed.Non-goals