Skip to content

fix: race in recent_visited_task audit field writes - #9943

Open
pablohashescobar wants to merge 1 commit into
previewfrom
fix/recent-visited-race
Open

pablohashescobar wants to merge 1 commit into
previewfrom
fix/recent-visited-race

Conversation

@pablohashescobar

@pablohashescobar pablohashescobar commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Description

recent_visited_task created a UserRecentVisit row and then ran a second save(update_fields=["created_by_id", "updated_by_id"]) to set the audit fields. If a concurrent task evicted that row in between (the cap-at-20 delete earlier in the task), the second save raised "Save with update_fields did not affect any rows".

This sets created_by_id / updated_by_id in the initial INSERT and saves once with disable_auto_set_user=True, so BaseModel.save doesn't null them (there is no request user in a background task). A unit test covers it.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Screenshots and Media (if applicable)

Test Scenarios

  • Run docker compose -f docker-compose-test.yml run --rm api-tests pytest plane/tests/unit/bg_tasks/test_recent_visited_task.py: a new visit has created_by_id and updated_by_id set to the user, and save is called exactly once.
  • Visit many entities quickly (more than 20 per user) and confirm no "Save with update_fields did not affect any rows" errors from recent_visited_task.

References

No linked work item.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability of recent-visit tracking. Newly recorded visits now retain the correct user attribution, helping keep recent activity accurate and consistent.

- Previously the task created the row, then called save(update_fields=...)
  to set created_by/updated_by. If a concurrent task evicted the row
  (the cap-at-20 delete) in between, the second save raised "Save with
  update_fields did not affect any rows".
- Set created_by_id/updated_by_id on the initial INSERT and pass
  disable_auto_set_user=True so BaseModel.save doesn't null them (there
  is no request user in a background task).
- Add a unit test asserting audit fields are set with a single save.
Copilot AI balanced review requested due to automatic review settings October 4, 2026 18:07
@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 61c7c028-f486-494a-8547-605a9f9d3b92
📥 Commits

Reviewing files that changed from the base of the PR and between c7a5afe and 5be187a.

📒 Files selected for processing (2)
  • apps/api/plane/bgtasks/recent_visited_task.py
  • apps/api/plane/tests/unit/bg_tasks/test_recent_visited_task.py

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.


📝 Walkthrough

Walkthrough

The new recent-visit path sets created_by_id and updated_by_id before saving, and disables automatic user assignment for that save. A unit test checks both audit fields and verifies that save is called once.

Changes

Recent visit creation

Layer / File(s) Summary
Set audit fields in one save
apps/api/plane/bgtasks/recent_visited_task.py, apps/api/plane/tests/unit/bg_tasks/test_recent_visited_task.py
The new-record path sets the audit fields before saving and uses disable_auto_set_user=True. The regression test checks both fields and verifies one save call.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 5be18

No actionable merge risk remains: the recent-visit creation path avoids the second write, and the regression test verifies the persisted audit fields.

Security Architecture Review

Security architecture risk: ⚪ Minimal · up to 5be18

The change preserves existing user and workspace ownership while saving audit fields together with the new visit. It removes a failure window without adding an entrypoint, increasing privileges, or weakening the reviewed access controls.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The reviewed change affects new recent-visit records in the existing user/workspace scope. It does not expand the task's argument sources, ownership scope, or authority in the compared execution paths.

Trust Boundaries and Controls

  • observed — Reviewed API callers enqueue visits using request.user.id and route-derived workspace/project context. The worker continues trusting its queued arguments rather than independently checking membership. This trust arrangement predates the patch; broker-level authorization and exhaustive caller coverage were not established.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the fix for the audit-field write race in recent_visited_task.
Description check ✅ Passed The description explains the race, the proposed fix, and the unit test. It includes all template sections and identifies that no work item is linked. The test scenarios do not confirm that the command…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The focused fix addresses the reported race and includes regression coverage, with no unresolved findings.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes a race in recent-visit tracking by setting audit fields during the initial insert.

Changes:

  • Removes the race-prone follow-up save while preserving audit fields.
  • Adds regression coverage for audit values and a single save call.
File Description
apps/​api/​plane/​tests/​unit/​bg_tasks/​test_recent_visited_task.py Verifies audit fields and single-save behavior.
apps/​api/​plane/​bgtasks/​recent_visited_task.py Sets audit fields during creation without automatic user overrides.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants