fix(safety): harden dedup planning and deletion consent - #730
Conversation
Make RFC822 Message-ID derivation a confirmed, atomic operation; require durable client-side consent for remote deletion; and document the case-insensitive email identifier invariant.
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
|
looking |
Deduplication could continue after a confirmed Message-ID derivation stopped matching the archive. It could also show incorrect consent text when the CLI and daemon used different plan fields. Fail closed when backfill state changes. Treat malformed bracketed IDs as insufficient evidence for a merge while preserving existing import thread keys. Require an explicit CLI/daemon plan protocol, and capture remote-delete consent context before a daemon subprocess can be reparented. Keep derivation writes atomic. Bounded reads and exact row checks reduce archive load without weakening the confirmed plan. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
|
Implemented the review follow-ups. Deduplication now stops and asks the user to rerun if the approved Message-ID work no longer matches the archive. It will not go on to hide messages when that update is stale or affects no rows. Other changes:
I kept all derived-ID writes in one transaction. I also kept source parsing in the approval scan because the approval must match the exact source data. Per-message reads and unnecessary rescans are gone. |
roborev: Combined Review (
|
PostgreSQL can hold an early row lock while it waits for a later row without delivering either row to the Go driver. The previous test waited for driver delivery, so it timed out even when lock ordering was correct. Observe the database lock itself after the query starts. This keeps the test focused on the concurrency behavior that the backfill owns. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Deduplication could trust a stored Message-ID when available raw MIME did not contain a usable matching header. Stale metadata could then create a duplicate group that the source bytes did not confirm. Require available raw MIME to confirm the stored value. Recover top-level headers when full MIME parsing fails, and reject missing, malformed, mismatched, or unreadable IDs. Messages without raw MIME still use their stored Message-ID. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
PostgreSQL cannot store NUL bytes in text values, but the backfill planner approved derived Message-IDs that contained them. Applying an approved plan then aborted the entire transaction. Classify these values as failed candidates during both planning and apply on PostgreSQL. Keep SQLite's existing NUL behavior unchanged. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
|
Follow-up on the latest automated review: importer thread normalization has not changed in this PR. |
What changed
Why
Dedup preview could write derived metadata before confirmation, outside the backup boundary. Remote deletion only had a one-command environment gate, which was awkward for headless clients and ambiguous across the CLI/daemon boundary. The identifier comparison rule was correct in code but easy for the next caller to bypass. This keeps preview read-only, makes confirmed writes fail closed, and keeps destructive consent explicit and client-owned.
Usage
Remote deletion remains disabled by default. To opt in durably:
For one command:
The dedup command and flags are unchanged; its confirmation now includes any planned Message-ID derivations.
Closes #312
Closes #314
Closes #315