Skip to content

approve_request creates the want before persisting the status update — orphaned want and duplicate acquisition on DB failure #396

Description

@forkwright

Finding

approve_request calls monitor.create_want (which commits the want entry to its store) and then calls repo::update_status (which updates the request row in SQLite). These two operations are not atomic and have no compensation between them. If update_status fails after create_want succeeds, the want is committed but the request remains in Submitted state. A subsequent admin approval of the same request creates a second want.

Evidence

crates/aitesis/src/approval.rs:85 commits the want first:

let want_id = monitor.create_want(&request).await?;

crates/aitesis/src/approval.rs:89-100 then updates the request row via crate::repo::update_status(pool, ...). There is no rollback of the want and no idempotency guard between the two calls, so a failed update_status leaves the want committed while the request stays Submitted and re-approvable.

Why this matters

Duplicate wants drive duplicate acquisition jobs — two downloads of the same media. The monitoring layer does not deduplicate, so this produces redundant network egress and conflicting imports plus wasted storage. On a counter-surveillance device, duplicated fetches of identical content are an observable traffic-pattern anomaly that enlarges the network fingerprint visible to an adversary monitoring the link, and the conflicting imports leave inconsistent state that is hard to reconcile.

Desired correction

Create the want only after the status update succeeds, or introduce a two-phase commit (move the request to a Transitioning state, create the want, then finalize), or make create_want idempotent by upserting on request ID so a re-approval after a partial failure reuses the existing want. Done when: a failed update_status leaves no orphaned want in the monitor store.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions