Skip to content

[policy-alert] Replace non-atomic delete+add in ChatDatabase with transactional upsert #987

@dislovelhl

Description

@dislovelhl

Context

Follow-up from PR #952. _persist_policy_block_if_needed in src/gaia/ui/_chat_helpers.py updates a persisted message via non-atomic delete_messageadd_message. The author acknowledged this with a comment: "ChatDatabase is single-writer SQLite today; rtk make this replacement transactional before moving the chat DB to a multi-writer backend." This pattern appears twice in the file.

Risk

Between DELETE and INSERT a crash, exception, or future multi-writer access can leave the session without the policy-block message — silent data loss. With SQLite WAL mode enabled the window is narrow but non-zero.

Fix

Add ChatDatabase.upsert_message(session_id, msg_id, content, ...) backed by a single INSERT OR REPLACE or BEGIN IMMEDIATE transaction. Replace both call sites in _chat_helpers.py:

# Before
db.delete_message(request.session_id, persisted_policy_block_msg_id)
persisted_policy_block_msg_id = db.add_message(...)

# After
persisted_policy_block_msg_id = db.upsert_message(
    request.session_id, persisted_policy_block_msg_id, ...
)

Files

  • src/gaia/ui/chat_database.py — add upsert_message
  • src/gaia/ui/_chat_helpers.py — replace both delete+add call sites
  • tests/unit/chat/ — add concurrent-write and crash-recovery tests

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-uiAgent UI changesbugSomething isn't workingdomain:surfacesAgent UI, Telegram, WhatsApp, Slack/Discord, mobilerobustnessReliability, error handling, and hardening

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions