Skip to content

[GIT-175] fix: completed_at updation logic for work items#9044

Merged
sriramveeraghanta merged 3 commits into
previewfrom
fix-issue-completed-at
May 12, 2026
Merged

[GIT-175] fix: completed_at updation logic for work items#9044
sriramveeraghanta merged 3 commits into
previewfrom
fix-issue-completed-at

Conversation

@sangeethailango
Copy link
Copy Markdown
Member

@sangeethailango sangeethailango commented May 11, 2026

This pull request refactors how the Issue model in issue.py handles state management and tracking of changes. The main improvements include extracting logic for assigning default states and updating the completed_at field into dedicated helper methods, and enabling change tracking for the state_id field. These changes improve code clarity, maintainability, and ensure that state transitions are tracked more reliably.

State management and tracking improvements:

  • The Issue model now inherits from ChangeTrackerMixin and explicitly tracks changes to the state_id field, enabling more robust detection of state changes.
  • The logic for assigning a default state and updating the completed_at field has been refactored into two private methods: _ensure_default_state and _sync_completed_at, improving code organization and readability. [1] [2]
  • The save method in Issue now delegates state assignment and completed_at synchronization to these new helper methods, ensuring consistent behavior and reducing code duplication.

Code organization:

  • The import of ChangeTrackerMixin has been moved to the main import statement for consistency.

Summary by CodeRabbit

  • Refactor
    • Added change-tracking for issue state to centralize and standardize state handling and completion logic.
  • Bug Fixes
    • Default issue state is now assigned more reliably when missing.
    • Issue completion timestamp now sets or clears correctly when state transitions to/from a completed state.
    • Import errors during state resolution are now logged instead of being silently ignored.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fbbab2f3-59a1-4d29-b204-30a4be8b2aa4

📥 Commits

Reviewing files that changed from the base of the PR and between 20b3f6d and 1eb5bea.

📒 Files selected for processing (1)
  • apps/api/plane/db/models/issue.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/api/plane/db/models/issue.py

📝 Walkthrough

Walkthrough

The Issue model now inherits ChangeTrackerMixin and tracks state_id. save() delegates default-state assignment to _ensure_default_state() and completed_at updates to _sync_completed_at(), which sets or clears completed_at when state transitions involve the "completed" group.

Changes

Issue Model State Tracking Refactor

Layer / File(s) Summary
Imports and Dependencies
apps/api/plane/db/models/issue.py
Added ChangeTrackerMixin import and reordered related imports.
Model Declaration and Tracking
apps/api/plane/db/models/issue.py
Issue now inherits ChangeTrackerMixin and declares TRACKED_FIELDS = ["state_id"].
save() Delegation
apps/api/plane/db/models/issue.py
save() now calls _ensure_default_state() and _sync_completed_at(kwargs) instead of inline default-state/completed_at logic.
Default State & completed_at Helpers
apps/api/plane/db/models/issue.py
Added _ensure_default_state() (selects project default non-triage or fallback, logs ImportError) and _sync_completed_at() (sets/clears completed_at and adds it to update_fields when appropriate).

Sequence Diagram(s)

sequenceDiagram
  participant Issue
  participant Project
  participant State
  Issue->>Project: get_default_non_triage_state()
  Project->>Issue: State or None
  alt default found
    Issue->>State: assign to self.state
  else fallback
    Project->>State: get_any_non_triage_state()
    State->>Issue: assign to self.state
  end
  Issue->>Issue: determine state.group == "completed"
  alt completed
    Issue->>Issue: set completed_at = timezone.now()
  else not completed
    Issue->>Issue: clear completed_at
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A mixin hops into the class tonight,
Watching state ids flicker bright,
Helpers tuck timestamps with care,
Defaults found from project lair,
Small hops, tidy code, a refactor’s light.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. 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 and concisely summarizes the main change: improving the completed_at update logic for work items through state management refactoring.
Description check ✅ Passed The description covers the main refactoring work and improvements, but does not include the template sections like Type of Change, Test Scenarios, or References.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-issue-completed-at

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 and usage tips.

@makeplane
Copy link
Copy Markdown

makeplane Bot commented May 11, 2026

Linked to Plane Work Item(s)

This comment was auto-generated by Plane

@sangeethailango sangeethailango marked this pull request as ready for review May 11, 2026 09:56
Copilot AI review requested due to automatic review settings May 11, 2026 09:56
Comment thread apps/api/plane/db/models/issue.py Fixed
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/plane/db/models/issue.py`:
- Around line 181-182: The helper calls _ensure_default_state() and
_sync_completed_at(kwargs) must be skipped for partial saves that don't include
state to avoid writing completed_at without state_id; change the save/update
code paths (the call sites invoking _ensure_default_state and _sync_completed_at
in the Issue model) to only invoke these helpers when update_fields is None
(full save) or when update_fields contains the state-related field names
('state' or 'state_id'); apply the same guard to the other occurrence of these
helpers in the code around the second block (previously noted at lines 240-255)
so both spots only mutate completed_at/state when state is being persisted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 90f82593-c53f-41c3-b1a2-1f15a60ea148

📥 Commits

Reviewing files that changed from the base of the PR and between 4c1bdd1 and e90693f.

📒 Files selected for processing (1)
  • apps/api/plane/db/models/issue.py

Comment thread apps/api/plane/db/models/issue.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors the Issue model’s state-handling logic to make default state assignment and completed_at synchronization more maintainable and to avoid updating completed_at on unrelated saves by tracking state_id changes via ChangeTrackerMixin.

Changes:

  • Issue now inherits from ChangeTrackerMixin and tracks state_id changes via TRACKED_FIELDS.
  • Extracts default state assignment into _ensure_default_state().
  • Extracts completed_at update logic into _sync_completed_at() and adjusts update_fields to include completed_at when needed.

Comment thread apps/api/plane/db/models/issue.py
Comment thread apps/api/plane/db/models/issue.py Outdated
Comment thread apps/api/plane/db/models/issue.py
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
apps/api/plane/db/models/issue.py (1)

181-182: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Guard state side effects behind update_fields check.

These helpers currently run even for partial saves that exclude the state field. This can cause data corruption: if issue.state is modified in memory but save(update_fields=["name"]) is called, _sync_completed_at will write completed_at without persisting the new state_id, leaving the database inconsistent.

The previous review comment on lines 181-182 correctly identified this issue and provided a fix. Please apply the suggested guard:

update_fields = kwargs.get("update_fields")
state_is_being_saved = (
    update_fields is None
    or "state" in update_fields
    or "state_id" in update_fields
)

if self._state.adding or state_is_being_saved:
    self._ensure_default_state()
    kwargs = self._sync_completed_at(kwargs)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/plane/db/models/issue.py` around lines 181 - 182, The helpers
_ensure_default_state and _sync_completed_at are being executed even for partial
saves, causing completed_at to be updated when state isn't being persisted;
modify the save (or the method containing the shown lines) to first compute
update_fields = kwargs.get("update_fields") and determine state_is_being_saved =
(update_fields is None or "state" in update_fields or "state_id" in
update_fields), then only call self._ensure_default_state() and kwargs =
self._sync_completed_at(kwargs) when self._state.adding or state_is_being_saved
is true so side effects are guarded behind the update_fields check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@apps/api/plane/db/models/issue.py`:
- Around line 181-182: The helpers _ensure_default_state and _sync_completed_at
are being executed even for partial saves, causing completed_at to be updated
when state isn't being persisted; modify the save (or the method containing the
shown lines) to first compute update_fields = kwargs.get("update_fields") and
determine state_is_being_saved = (update_fields is None or "state" in
update_fields or "state_id" in update_fields), then only call
self._ensure_default_state() and kwargs = self._sync_completed_at(kwargs) when
self._state.adding or state_is_being_saved is true so side effects are guarded
behind the update_fields check.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 99abe9ca-04ed-4da0-a9e1-c3e27f0b0ada

📥 Commits

Reviewing files that changed from the base of the PR and between e90693f and 20b3f6d.

📒 Files selected for processing (1)
  • apps/api/plane/db/models/issue.py

@sriramveeraghanta sriramveeraghanta merged commit 4225bc5 into preview May 12, 2026
13 checks passed
@sriramveeraghanta sriramveeraghanta deleted the fix-issue-completed-at branch May 12, 2026 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants