Commit c6fc673
authored
fix(conversations): reject reprocessing a soft-deleted conversation (#10270)
## What
A soft-delete/tombstone data-integrity gap: `POST
/v1/conversations/{id}/reprocess` regenerates a soft-deleted
conversation's derived data — resurrecting content the user deleted.
`reprocess_conversation` fetches through
`_get_valid_conversation_by_id`, which does not filter soft-deleted
tombstones (`get_conversation` returns them; the helper only 404s on a
missing doc). It then runs `process_conversation(force_process=True,
is_reprocess=True)`, which regenerates structured data, action items,
**memories** and embeddings. So reprocessing a deleted conversation —
via a direct API call, or a delete-vs-reprocess race — re-derives the
user's memories / action items / embeddings from content they deleted.
## Fix
Reject a **deleted** conversation in `reprocess_conversation` (404),
while still allowing a **discarded** one — which reprocess intentionally
revives (per its docstring, and the `eligible_merge_target` contract).
Checked on the raw doc because the `Conversation` model does not carry
`deleted`.
## Repairing the failure-class boundary
This is the **third instance** of one tombstone-eligibility contract —
*a soft-deleted tombstone must not have content operations applied, or
deleted data resurfaces*:
- sync merge target — #10119 (`eligible_merge_target`)
- user-initiated merge — #10262
- reprocess — this PR
Per AGENTS.md ("if two or more recent fixes share the cause, add a
reusable guard surface"), rather than a third point-fix I extracted the
shared **`is_soft_deleted`** predicate and converged
`eligible_merge_target` onto it (behaviour-preserving), so the reprocess
guard and the sync guard share one definition. #10262's inline merge
check can adopt it too — a small follow-up rather than re-touching that
merged path here; formalizing a named failure class is a reasonable
registry follow-up.
## Tests (hermetic)
- `test_reprocess_tombstone_guard.py` — the predicate (deleted →
tombstone; discarded / plain / None → not), reprocess **rejects** a
deleted conversation (404, `process_conversation` never called), and
still **allows** a discarded one.
- Existing `eligible_merge_target` and merge-validation tests stay green
(behaviour-preserving refactor). **49 passed.**
## Product invariants affected
none
Failure-Class: none
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/BasedHardware/omi/pull/10270?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->4 files changed
Lines changed: 90 additions & 3 deletions
File tree
- .github/scripts/product_file_line_count_ratchet_baseline
- backend
- database
- routers
- tests/unit
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1524 | 1524 | | |
1525 | 1525 | | |
1526 | 1526 | | |
| 1527 | + | |
| 1528 | + | |
| 1529 | + | |
| 1530 | + | |
| 1531 | + | |
| 1532 | + | |
| 1533 | + | |
| 1534 | + | |
| 1535 | + | |
| 1536 | + | |
| 1537 | + | |
| 1538 | + | |
| 1539 | + | |
| 1540 | + | |
| 1541 | + | |
1527 | 1542 | | |
1528 | 1543 | | |
1529 | 1544 | | |
| |||
1532 | 1547 | | |
1533 | 1548 | | |
1534 | 1549 | | |
1535 | | - | |
| 1550 | + | |
1536 | 1551 | | |
1537 | 1552 | | |
1538 | 1553 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
318 | 318 | | |
319 | 319 | | |
320 | 320 | | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
321 | 329 | | |
322 | 330 | | |
323 | 331 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
0 commit comments