Repository navigation
Conversation
Two splits of the same person could each see an id the other was about to move and together leave the person with no live distinct id. The SplitPerson RPC now claims the source person's lifecycle mark before any row lock, as ingestion merges and the tombstone RPC do, and then refuses with FailedPrecondition a split that would leave no live distinct id. A held mark or row fails the call within a 2s lock timeout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tombstone RPC locks persons in id order, and the split locked its target persons in no particular order, so a split and a tombstone call naming two of the same persons could deadlock. The comment on the lock timeout now says it bounds each wait, not the whole call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
🤖 CI report✅ Trunk lane — non-backend laneThis PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.
|
| File | Comment lines | Added lines |
|---|---|---|
rust/personhog-replica/src/storage/postgres/person.rs |
9 | 96 |
rust/personhog-replica/tests/storage_tests.rs |
4 | 145 |
This check does not block merging. It updates on every push and clears when the share drops.
The merge queue keeps Python and Rust changes in separate lanes, so the SplitPerson lifecycle mark change moves to #116730. This branch keeps the API and task checks only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Risk: No findings This increment rewords comments, routes the split's FailedPrecondition error through the shared converter (same gRPC status, now also counted in a metric), and adds a lock-timeout test. No security-relevant behavior changed since the last review, which found no issues. Sentinel reviewed |
A refused split now goes through the shared error conversion, so it is logged and counted in personhog_replica_storage_errors_total like other refusals. A new test holds the source's mark past the lock timeout and checks the split rolls back with nothing moved. Comments are shorter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
Two splits of the same person, run at once, can each see an ID the other is about to move. Together they leave the person with no live distinct ID.
#116701 checks single requests in Python. Only the database transaction can stop the concurrent case.
Changes
SplitPersonclaims the source person's lifecycle mark before any row lock. Ingestion merges and the tombstone RPC use the same mark.FailedPreconditiona split that would leave no live distinct ID.Note
A split now briefly blocks ingestion merges into the same person. The manual
detach_distinct_idjob takes no mark, so it can still race a split.How did you test this code?
Test rationale: no storage test covered a split that empties a person, or a split racing another writer.
cargo test, clippy, fmt andsqlx prepare --checklocally.Release status
Docs update
None.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Claude Opus 5.5. Skills:
/reviewing-personhog-protocol,/writing-tests,/writing-code-comments,/writing-pr-descriptions.🤖 Generated with Claude Code